~ubuntu-branches/ubuntu/wily/dovecot/wily-proposed

« back to all changes in this revision

Viewing changes to src/plugins/fts/fts-parser-tika.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2015-09-14 13:58:42 UTC
  • mfrom: (4.1.54 sid)
  • Revision ID: package-import@ubuntu.com-20150914135842-jhpp689shskxt0hu
Tags: 1:2.2.18-2ubuntu1
* Merge with Debian (after 552 days); remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
* d/control: Drop dovecot-postfix package as its no longer required.
* Rename init.d script to work with the dh_installinit --name option, so
  that it comes back. (LP: #1323274)
* d/dovecot-core.config: Drop db_input for ssl-cert-exists; this message
  not actually an error, is documented in the README.Debian, and blocks
  automated upgrades (LP: #1278897).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2014-2015 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "ioloop.h"
 
5
#include "istream.h"
 
6
#include "module-context.h"
 
7
#include "http-url.h"
 
8
#include "http-client.h"
 
9
#include "message-parser.h"
 
10
#include "mail-user.h"
 
11
#include "fts-parser.h"
 
12
 
 
13
#define TIKA_USER_CONTEXT(obj) \
 
14
        MODULE_CONTEXT(obj, fts_parser_tika_user_module)
 
15
 
 
16
struct fts_parser_tika_user {
 
17
        union mail_user_module_context module_ctx;
 
18
        struct http_url *http_url;
 
19
};
 
20
 
 
21
struct tika_fts_parser {
 
22
        struct fts_parser parser;
 
23
        struct mail_user *user;
 
24
        struct http_client_request *http_req;
 
25
 
 
26
        struct ioloop *ioloop;
 
27
        struct io *io;
 
28
        struct istream *payload;
 
29
 
 
30
        bool failed;
 
31
};
 
32
 
 
33
static struct http_client *tika_http_client = NULL;
 
34
static MODULE_CONTEXT_DEFINE_INIT(fts_parser_tika_user_module,
 
35
                                  &mail_user_module_register);
 
36
 
 
37
static int
 
38
tika_get_http_client_url(struct mail_user *user, struct http_url **http_url_r)
 
39
{
 
40
        struct fts_parser_tika_user *tuser = TIKA_USER_CONTEXT(user);
 
41
        struct http_client_settings http_set;
 
42
        const char *url, *error;
 
43
 
 
44
        url = mail_user_plugin_getenv(user, "fts_tika");
 
45
        if (url == NULL) {
 
46
                /* fts_tika disabled */
 
47
                return -1;
 
48
        }
 
49
 
 
50
        if (tuser != NULL) {
 
51
                *http_url_r = tuser->http_url;
 
52
                return *http_url_r == NULL ? -1 : 0;
 
53
        }
 
54
 
 
55
        tuser = p_new(user->pool, struct fts_parser_tika_user, 1);
 
56
        MODULE_CONTEXT_SET(user, fts_parser_tika_user_module, tuser);
 
57
 
 
58
        if (http_url_parse(url, NULL, 0, user->pool,
 
59
                           &tuser->http_url, &error) < 0) {
 
60
                i_error("fts_tika: Failed to parse HTTP url %s: %s", url, error);
 
61
                return -1;
 
62
        }
 
63
 
 
64
        if (tika_http_client == NULL) {
 
65
                memset(&http_set, 0, sizeof(http_set));
 
66
                http_set.max_idle_time_msecs = 100;
 
67
                http_set.max_parallel_connections = 1;
 
68
                http_set.max_pipelined_requests = 1;
 
69
                http_set.max_redirects = 1;
 
70
                http_set.max_attempts = 3;
 
71
                http_set.connect_timeout_msecs = 5*1000;
 
72
                http_set.request_timeout_msecs = 60*1000;
 
73
                http_set.debug = user->mail_debug;
 
74
                tika_http_client = http_client_init(&http_set);
 
75
        }
 
76
        *http_url_r = tuser->http_url;
 
77
        return 0;
 
78
}
 
79
 
 
80
static void
 
81
fts_tika_parser_response(const struct http_response *response,
 
82
                         struct tika_fts_parser *parser)
 
83
{
 
84
        i_assert(parser->payload == NULL);
 
85
 
 
86
        switch (response->status) {
 
87
        case 200:
 
88
                /* read response */
 
89
                if (response->payload == NULL)
 
90
                        parser->payload = i_stream_create_from_data("", 0);
 
91
                else {
 
92
                        i_stream_ref(response->payload);
 
93
                        parser->payload = response->payload;
 
94
                }
 
95
                break;
 
96
        case 204: /* empty response */
 
97
        case 415: /* Unsupported Media Type */
 
98
        case 422: /* Unprocessable Entity */
 
99
                if (parser->user->mail_debug) {
 
100
                        i_debug("fts_tika: PUT %s failed: %u %s",
 
101
                                mail_user_plugin_getenv(parser->user, "fts_tika"),
 
102
                                response->status, response->reason);
 
103
                }
 
104
                parser->payload = i_stream_create_from_data("", 0);
 
105
                break;
 
106
        default:
 
107
                i_error("fts_tika: PUT %s failed: %u %s",
 
108
                        mail_user_plugin_getenv(parser->user, "fts_tika"),
 
109
                        response->status, response->reason);
 
110
                parser->failed = TRUE;
 
111
                break;
 
112
        }
 
113
        parser->http_req = NULL;
 
114
        io_loop_stop(current_ioloop);
 
115
}
 
116
 
 
117
static struct fts_parser *
 
118
fts_parser_tika_try_init(struct mail_user *user, const char *content_type,
 
119
                         const char *content_disposition)
 
120
{
 
121
        struct tika_fts_parser *parser;
 
122
        struct http_url *http_url;
 
123
        struct http_client_request *http_req;
 
124
 
 
125
        if (tika_get_http_client_url(user, &http_url) < 0)
 
126
                return NULL;
 
127
 
 
128
        parser = i_new(struct tika_fts_parser, 1);
 
129
        parser->parser.v = fts_parser_tika;
 
130
        parser->user = user;
 
131
 
 
132
        http_req = http_client_request(tika_http_client, "PUT",
 
133
                        http_url->host_name,
 
134
                        t_strconcat(http_url->path, http_url->enc_query, NULL),
 
135
                        fts_tika_parser_response, parser);
 
136
        http_client_request_set_port(http_req, http_url->port);
 
137
        http_client_request_set_ssl(http_req, http_url->have_ssl);
 
138
        http_client_request_add_header(http_req, "Content-Type", content_type);
 
139
        http_client_request_add_header(http_req, "Content-Disposition",
 
140
                                       content_disposition);
 
141
        http_client_request_add_header(http_req, "Accept", "text/plain");
 
142
 
 
143
        parser->http_req = http_req;
 
144
        return &parser->parser;
 
145
}
 
146
 
 
147
static void fts_parser_tika_more(struct fts_parser *_parser,
 
148
                                 struct message_block *block)
 
149
{
 
150
        struct tika_fts_parser *parser = (struct tika_fts_parser *)_parser;
 
151
        const unsigned char *data;
 
152
        size_t size;
 
153
        ssize_t ret;
 
154
 
 
155
        if (block->size > 0) {
 
156
                /* first we'll send everything to Tika */
 
157
                if (!parser->failed &&
 
158
                    http_client_request_send_payload(&parser->http_req,
 
159
                                                     block->data,
 
160
                                                     block->size) < 0)
 
161
                        parser->failed = TRUE;
 
162
                block->size = 0;
 
163
                return;
 
164
        }
 
165
 
 
166
        if (parser->payload == NULL) {
 
167
                /* read the result from Tika */
 
168
                if (!parser->failed &&
 
169
                    http_client_request_finish_payload(&parser->http_req) < 0)
 
170
                        parser->failed = TRUE;
 
171
                if (!parser->failed && parser->payload == NULL)
 
172
                        http_client_wait(tika_http_client);
 
173
                if (parser->failed)
 
174
                        return;
 
175
                i_assert(parser->payload != NULL);
 
176
        }
 
177
        /* continue returning data from Tika */
 
178
        while ((ret = i_stream_read_data(parser->payload, &data, &size, 0)) == 0) {
 
179
                if (parser->failed)
 
180
                        return;
 
181
                /* wait for more input from Tika */
 
182
                if (parser->ioloop == NULL) {
 
183
                        parser->ioloop = io_loop_create();
 
184
                        parser->io = io_add_istream(parser->payload, io_loop_stop,
 
185
                                                    current_ioloop);
 
186
                } else {
 
187
                        io_loop_set_current(parser->ioloop);
 
188
                }
 
189
                io_loop_run(current_ioloop);
 
190
        }
 
191
        if (size > 0) {
 
192
                i_assert(ret > 0);
 
193
                block->data = data;
 
194
                block->size = size;
 
195
                i_stream_skip(parser->payload, size);
 
196
        } else {
 
197
                /* finished */
 
198
                i_assert(ret == -1);
 
199
                if (parser->payload->stream_errno != 0) {
 
200
                        i_error("read(%s) failed: %s",
 
201
                                i_stream_get_name(parser->payload),
 
202
                                i_stream_get_error(parser->payload));
 
203
                        parser->failed = TRUE;
 
204
                }
 
205
        }
 
206
}
 
207
 
 
208
static int fts_parser_tika_deinit(struct fts_parser *_parser)
 
209
{
 
210
        struct tika_fts_parser *parser = (struct tika_fts_parser *)_parser;
 
211
        int ret = parser->failed ? -1 : 0;
 
212
 
 
213
        if (parser->ioloop != NULL) {
 
214
                io_remove(&parser->io);
 
215
                io_loop_destroy(&parser->ioloop);
 
216
        }
 
217
        if (parser->payload != NULL)
 
218
                i_stream_unref(&parser->payload);
 
219
        /* FIXME: kludgy, http_req should be NULL here if we don't want to
 
220
           free it. requires lib-http changes. */
 
221
        if (parser->http_req != NULL)
 
222
                http_client_request_abort(&parser->http_req);
 
223
        i_free(parser);
 
224
        return ret;
 
225
}
 
226
 
 
227
static void fts_parser_tika_unload(void)
 
228
{
 
229
        if (tika_http_client != NULL)
 
230
                http_client_deinit(&tika_http_client);
 
231
}
 
232
 
 
233
struct fts_parser_vfuncs fts_parser_tika = {
 
234
        fts_parser_tika_try_init,
 
235
        fts_parser_tika_more,
 
236
        fts_parser_tika_deinit,
 
237
        fts_parser_tika_unload
 
238
};