66
67
/* Protocol callback functions. */
68
69
static const char *_http_line(const void *data, size_t data_size,
69
size_t *line_size, size_t *offset)
70
size_t& line_size, size_t& offset)
71
const char *start= (const char *)data + *offset;
72
const char *start= (const char *)data +offset;
74
end= (const char *)memchr(start, '\n', data_size - *offset);
74
const char *end= (const char *)memchr(start, '\n', data_size -offset);
78
*offset+= (size_t)(end - start) + 1;
80
offset+= size_t(end - start) +1;
80
82
if (end != start && *(end - 1) == '\r')
83
*line_size= (size_t)(end - start);
87
line_size= size_t(end - start);
88
static void _http_free(gearman_server_con_st *connection __attribute__ ((unused)),
92
static void _http_free(gearman_server_con_st *, void *context)
91
gearmand_info("HTTP connection disconnected");
94
gearmand_debug("HTTP connection disconnected");
92
95
gearmand::protocol::HTTP *http= (gearmand::protocol::HTTP *)context;
97
100
void *data, size_t data_size,
98
101
gearmand_error_t *ret_ptr)
100
gearmand_info("Sending HTTP response");
104
103
gearmand::protocol::HTTP *http= (gearmand::protocol::HTTP *)gearmand_connection_protocol_context(connection);
106
105
if (packet->command != GEARMAN_COMMAND_WORK_COMPLETE and
109
108
(http->background() == false or
110
109
packet->command != GEARMAN_COMMAND_JOB_CREATED))
112
gearmand_info("Sending HTTP told to ignore packet");
111
gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM,
112
"Sending HTTP told to ignore packet: gearmand_command_t:%s",
113
gearman_strcommand(packet->command));
113
114
*ret_ptr= GEARMAN_IGNORE_PACKET;
117
if (http->method() == gearmand::protocol::HTTP::HEAD)
118
gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Sending HTTP response: Content-length:%"PRIu64" gearmand_command_t:%s response:%s",
119
uint64_t(packet->data_size), gearman_strcommand(packet->command),
120
gearmand::protocol::httpd::response(http->response()));
123
if (http->response() != gearmand::protocol::httpd::HTTP_OK)
125
pack_size= (size_t)snprintf((char *)data, data_size,
127
"Server: Gearman/" PACKAGE_VERSION "\r\n"
128
"Content-Length: 0\r\n"
130
int(http->response()), gearmand::protocol::httpd::response(http->response()));
132
else if (http->method() == gearmand::protocol::httpd::HEAD)
119
134
pack_size= (size_t)snprintf((char *)data, data_size,
120
135
"HTTP/1.0 200 OK\r\n"
126
141
(const char *)packet->arg[0],
127
142
(uint64_t)packet->data_size);
129
else if (http->method() == gearmand::protocol::HTTP::TRACE)
144
else if (http->method() == gearmand::protocol::httpd::TRACE)
131
146
pack_size= (size_t)snprintf((char *)data, data_size,
132
147
"HTTP/1.0 200 OK\r\n"
140
155
pack_size= (size_t)snprintf((char *)data, data_size,
141
156
"HTTP/1.0 200 OK\r\n"
142
157
"X-Gearman-Job-Handle: %.*s\r\n"
158
"X-Gearman-Command: %s\r\n"
143
159
"Content-Length: %"PRIu64"\r\n"
144
160
"Server: Gearman/" PACKAGE_VERSION "\r\n"
146
packet->command == GEARMAN_COMMAND_JOB_CREATED ? (int)packet->arg_size[0] : (int)packet->arg_size[0] - 1,
147
(const char *)packet->arg[0],
148
(uint64_t)packet->data_size);
162
packet->command == GEARMAN_COMMAND_JOB_CREATED ? int(packet->arg_size[0]) : int(packet->arg_size[0] - 1), (const char *)packet->arg[0],
163
gearman_strcommand(packet->command),
164
uint64_t(packet->data_size));
151
167
if (pack_size > data_size)
153
gearmand_info("Sending HTTP had to flush");
169
gearmand_debug("Sending HTTP had to flush");
154
170
*ret_ptr= GEARMAN_FLUSH_DATA;
158
if (! (http->keep_alive()))
174
if (http->keep_alive() == false)
160
176
gearman_io_set_option(&connection->con, GEARMAND_CON_CLOSE_AFTER_FLUSH, true);
163
179
*ret_ptr= GEARMAN_SUCCESS;
164
181
return pack_size;
166
184
static size_t _http_unpack(gearmand_packet_st *packet, gearman_server_con_st *connection,
167
185
const void *data, size_t data_size,
168
186
gearmand_error_t *ret_ptr)
170
gearmand::protocol::HTTP *http;
171
188
const char *unique= "-";
172
189
size_t unique_size= 2;
173
190
gearmand_job_priority_t priority= GEARMAND_JOB_PRIORITY_NORMAL;
177
194
/* Get the request line first. */
178
195
size_t request_size;
179
196
size_t offset= 0;
180
const char *request= _http_line(data, data_size, &request_size, &offset);
197
const char *request= _http_line(data, data_size, request_size, offset);
181
198
if (request == NULL or request_size == 0)
183
200
gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Zero length request made");
188
http= (gearmand::protocol::HTTP *)gearmand_connection_protocol_context(connection);
205
gearmand::protocol::HTTP *http= (gearmand::protocol::HTTP *)gearmand_connection_protocol_context(connection);
191
208
/* Parse out the method, URI, and HTTP version from the request line. */
196
213
gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad request line: %.*s", (uint32_t)request_size, request);
197
*ret_ptr= GEARMAN_INVALID_PACKET;
214
http->set_response(gearmand::protocol::httpd::HTTP_NOT_FOUND);
215
*ret_ptr= GEARMAN_SUCCESS;
203
221
if (method_size == 3 and strncmp(method, "GET", 3) == 0)
205
http->set_method(gearmand::protocol::HTTP::GET);
223
http->set_method(gearmand::protocol::httpd::GET);
207
225
else if (method_size == 3 and strncmp(method, "PUT", 3) == 0)
209
http->set_method(gearmand::protocol::HTTP::PUT);
227
http->set_method(gearmand::protocol::httpd::PUT);
211
229
else if (method_size == 4 and strncmp(method, "POST", 4) == 0)
213
http->set_method(gearmand::protocol::HTTP::POST);
231
http->set_method(gearmand::protocol::httpd::POST);
215
233
else if (method_size == 4 and strncmp(method, "HEAD", 4) == 0)
217
http->set_method(gearmand::protocol::HTTP::HEAD);
235
http->set_method(gearmand::protocol::httpd::HEAD);
219
237
else if (method_size == 5 and strncmp(method, "TRACE", 5) == 0)
221
http->set_method(gearmand::protocol::HTTP::TRACE);
239
http->set_method(gearmand::protocol::httpd::TRACE);
225
243
gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad method: %.*s", (uint32_t)method_size, method);
226
*ret_ptr= GEARMAN_INVALID_PACKET;
244
http->set_response(gearmand::protocol::httpd::HTTP_METHOD_NOT_ALLOWED);
245
*ret_ptr= GEARMAN_SUCCESS;
249
gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "METHOD: %s", str_method(http->method()));
251
gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "URI: %s", uri);
230
253
while (*uri == ' ')
257
gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "URI: %s", uri);
235
259
while (*uri == '/')
263
gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "URI: %s", uri);
240
265
const char *version= (const char *)memchr(uri, ' ', request_size - (size_t)(uri - request));
241
266
if (version == NULL)
249
274
ptrdiff_t uri_size= version -uri;
250
275
switch (http->method())
252
case gearmand::protocol::HTTP::POST:
253
case gearmand::protocol::HTTP::PUT:
254
case gearmand::protocol::HTTP::GET:
277
case gearmand::protocol::httpd::POST:
278
case gearmand::protocol::httpd::PUT:
279
case gearmand::protocol::httpd::GET:
255
280
if (uri_size == 0)
257
282
gearmand_error("must give function name in URI");
258
*ret_ptr= GEARMAN_INVALID_PACKET;
283
http->set_response(gearmand::protocol::httpd::HTTP_NOT_FOUND);
262
case gearmand::protocol::HTTP::TRACE:
263
case gearmand::protocol::HTTP::HEAD:
286
case gearmand::protocol::httpd::TRACE:
287
case gearmand::protocol::httpd::HEAD:
272
296
size_t version_size= request_size - (size_t)(version - request);
273
if (version_size == 8 && !strncasecmp(version, "HTTP/1.1", 8))
297
if (false and version_size == 8 and strncasecmp(version, "HTTP/1.1", 8) == 0)
275
299
http->set_keep_alive(true);
277
else if (version_size != 8 || strncasecmp(version, "HTTP/1.0", 8))
301
else if (version_size == 8 and strncasecmp(version, "HTTP/1.1", 8) == 0)
279
306
gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad version: %.*s", (uint32_t)version_size, version);
280
307
*ret_ptr= GEARMAN_INVALID_PACKET;
284
311
/* Loop through all the headers looking for ones of interest. */
285
312
const char *header;
286
313
size_t header_size;
287
while ((header= _http_line(data, data_size, &header_size, &offset)) != NULL)
314
while ((header= _http_line(data, data_size, header_size, offset)) != NULL)
289
316
if (header_size == 0)
332
359
/* Make sure we received the end of headers. */
360
if (header == NULL and http->response() == gearmand::protocol::httpd::HTTP_OK)
335
362
gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "No headers were found");
336
363
*ret_ptr= GEARMAN_IO_WAIT;
340
367
/* Request and all headers complete, build a packet based on HTTP request. */
341
368
packet->magic= GEARMAN_MAGIC_REQUEST;
343
if (http->method() == gearmand::protocol::HTTP::TRACE)
370
if (http->response() != gearmand::protocol::httpd::HTTP_OK)
372
packet->command= GEARMAN_COMMAND_ECHO_REQ;
374
*ret_ptr= gearmand_packet_pack_header(packet);
375
if (*ret_ptr != GEARMAN_SUCCESS)
380
packet->data_size= 0;
383
else if (http->method() == gearmand::protocol::httpd::TRACE)
345
385
packet->command= GEARMAN_COMMAND_ECHO_REQ;
353
393
packet->data_size= data_size;
354
394
packet->data= (const char*)data;
356
else if (http->method() == gearmand::protocol::HTTP::HEAD and uri_size == 0)
396
else if (http->method() == gearmand::protocol::httpd::HEAD and uri_size == 0)
358
398
packet->command= GEARMAN_COMMAND_ECHO_REQ;
438
_method(gearmand::protocol::HTTP::TRACE),
478
_method(gearmand::protocol::httpd::TRACE),
439
479
_background(false),
481
_http_response(gearmand::protocol::httpd::HTTP_OK)
442
483
command_line_options().add_options()
443
484
("http-port", boost::program_options::value(&global_port)->default_value(GEARMAN_PROTOCOL_HTTP_DEFAULT_PORT), "Port to listen on.");