~ubuntu-branches/debian/sid/gearmand/sid

« back to all changes in this revision

Viewing changes to libgearman-server/plugins/protocol/http/protocol.cc

  • Committer: Package Import Robot
  • Author(s): Stig Sandbeck Mathisen
  • Date: 2012-05-01 20:43:47 UTC
  • mfrom: (1.1.8)
  • Revision ID: package-import@ubuntu.com-20120501204347-qaifvvjkktvc9upu
Tags: 0.32-1
* Imported Upstream version 0.32
* Remove spelling patch included upstream
* Remove documentation patch, we do not rebuild documentation
* Remove memcached patch, fixed upstream
* Use dh_autoreconf
* Use copyright format 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
 
45
45
#include <config.h>
46
46
#include <libgearman-server/common.h>
 
47
#include <libgearman/strcommand.h>
47
48
 
48
49
#include <cstdio>
49
50
#include <cstdlib>
66
67
/* Protocol callback functions. */
67
68
 
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)
70
71
{
71
 
  const char *start= (const char *)data + *offset;
72
 
  const char *end;
 
72
  const char *start= (const char *)data +offset;
73
73
 
74
 
  end= (const char *)memchr(start, '\n', data_size - *offset);
 
74
  const char *end= (const char *)memchr(start, '\n', data_size -offset);
75
75
  if (end == NULL)
 
76
  {
76
77
    return NULL;
 
78
  }
77
79
 
78
 
  *offset+= (size_t)(end - start) + 1;
 
80
  offset+= size_t(end - start) +1;
79
81
 
80
82
  if (end != start && *(end - 1) == '\r')
 
83
  {
81
84
    end--;
 
85
  }
82
86
 
83
 
  *line_size= (size_t)(end - start);
 
87
  line_size= size_t(end - start);
84
88
 
85
89
  return start;
86
90
}
87
91
 
88
 
static void _http_free(gearman_server_con_st *connection __attribute__ ((unused)),
89
 
                       void *context)
 
92
static void _http_free(gearman_server_con_st *, void *context)
90
93
{
91
 
  gearmand_info("HTTP connection disconnected");
 
94
  gearmand_debug("HTTP connection disconnected");
92
95
  gearmand::protocol::HTTP *http= (gearmand::protocol::HTTP *)context;
93
96
  delete http;
94
97
}
97
100
                         void *data, size_t data_size,
98
101
                         gearmand_error_t *ret_ptr)
99
102
{
100
 
  gearmand_info("Sending HTTP response");
101
 
 
102
 
  size_t pack_size;
103
 
 
104
103
  gearmand::protocol::HTTP *http= (gearmand::protocol::HTTP *)gearmand_connection_protocol_context(connection);
105
104
 
106
105
  if (packet->command != GEARMAN_COMMAND_WORK_COMPLETE and
109
108
      (http->background() == false or
110
109
       packet->command != GEARMAN_COMMAND_JOB_CREATED))
111
110
  {
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;
114
115
    return 0;
115
116
  }
116
117
 
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()));
 
121
 
 
122
  size_t pack_size;
 
123
  if (http->response() != gearmand::protocol::httpd::HTTP_OK)
 
124
  {
 
125
    pack_size= (size_t)snprintf((char *)data, data_size,
 
126
                                "HTTP/1.0 %u %s\r\n"
 
127
                                "Server: Gearman/" PACKAGE_VERSION "\r\n"
 
128
                                "Content-Length: 0\r\n"
 
129
                                "\r\n",
 
130
                                int(http->response()), gearmand::protocol::httpd::response(http->response()));
 
131
  }
 
132
  else if (http->method() == gearmand::protocol::httpd::HEAD)
118
133
  {
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);
128
143
  }
129
 
  else if (http->method() == gearmand::protocol::HTTP::TRACE)
 
144
  else if (http->method() == gearmand::protocol::httpd::TRACE)
130
145
  {
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"
145
161
                                "\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));
149
165
  }
150
166
 
151
167
  if (pack_size > data_size)
152
168
  {
153
 
    gearmand_info("Sending HTTP had to flush");
 
169
    gearmand_debug("Sending HTTP had to flush");
154
170
    *ret_ptr= GEARMAN_FLUSH_DATA;
155
171
    return 0;
156
172
  }
157
173
 
158
 
  if (! (http->keep_alive()))
 
174
  if (http->keep_alive() == false)
159
175
  {
160
176
    gearman_io_set_option(&connection->con, GEARMAND_CON_CLOSE_AFTER_FLUSH, true);
161
177
  }
162
178
 
163
179
  *ret_ptr= GEARMAN_SUCCESS;
 
180
 
164
181
  return pack_size;
165
182
}
 
183
 
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)
169
187
{
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)
182
199
  {
183
200
    gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Zero length request made");
185
202
    return offset;
186
203
  }
187
204
 
188
 
  http= (gearmand::protocol::HTTP *)gearmand_connection_protocol_context(connection);
 
205
  gearmand::protocol::HTTP *http= (gearmand::protocol::HTTP *)gearmand_connection_protocol_context(connection);
189
206
  http->reset();
190
207
 
191
208
  /* Parse out the method, URI, and HTTP version from the request line. */
194
211
  if (uri == NULL)
195
212
  {
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;
198
216
    return 0;
199
217
  }
200
218
 
202
220
 
203
221
  if (method_size == 3 and strncmp(method, "GET", 3) == 0)
204
222
  {
205
 
    http->set_method(gearmand::protocol::HTTP::GET);
 
223
    http->set_method(gearmand::protocol::httpd::GET);
206
224
  }
207
225
  else if (method_size == 3 and strncmp(method, "PUT", 3) == 0)
208
226
  {
209
 
    http->set_method(gearmand::protocol::HTTP::PUT);
 
227
    http->set_method(gearmand::protocol::httpd::PUT);
210
228
  }
211
229
  else if (method_size == 4 and strncmp(method, "POST", 4) == 0)
212
230
  {
213
 
    http->set_method(gearmand::protocol::HTTP::POST);
 
231
    http->set_method(gearmand::protocol::httpd::POST);
214
232
  }
215
233
  else if (method_size == 4 and strncmp(method, "HEAD", 4) == 0)
216
234
  {
217
 
    http->set_method(gearmand::protocol::HTTP::HEAD);
 
235
    http->set_method(gearmand::protocol::httpd::HEAD);
218
236
  }
219
237
  else if (method_size == 5 and strncmp(method, "TRACE", 5) == 0)
220
238
  {
221
 
    http->set_method(gearmand::protocol::HTTP::TRACE);
 
239
    http->set_method(gearmand::protocol::httpd::TRACE);
222
240
  }
223
241
  else
224
242
  {
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;
227
246
    return 0;
228
247
  }
229
248
 
 
249
  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "METHOD: %s", str_method(http->method()));
 
250
 
 
251
  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "URI: %s", uri);
 
252
 
230
253
  while (*uri == ' ')
231
254
  {
232
255
    uri++;
233
256
  }
 
257
  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "URI: %s", uri);
234
258
 
235
259
  while (*uri == '/')
236
260
  {
237
261
    uri++;
238
262
  }
 
263
  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "URI: %s", uri);
239
264
 
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())
251
276
  {
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)
256
281
    {
257
282
      gearmand_error("must give function name in URI");
258
 
      *ret_ptr= GEARMAN_INVALID_PACKET;
259
 
      return 0;
 
283
      http->set_response(gearmand::protocol::httpd::HTTP_NOT_FOUND);
260
284
    }
261
285
 
262
 
  case gearmand::protocol::HTTP::TRACE:
263
 
  case gearmand::protocol::HTTP::HEAD:
 
286
  case gearmand::protocol::httpd::TRACE:
 
287
  case gearmand::protocol::httpd::HEAD:
264
288
    break;
265
289
  }
266
290
 
270
294
  }
271
295
 
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)
274
298
  {
275
299
    http->set_keep_alive(true);
276
300
  }
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)
 
302
  {
 
303
  }
 
304
  else
278
305
  {
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)
288
315
  {
289
316
    if (header_size == 0)
290
317
    {
330
357
  }
331
358
 
332
359
  /* Make sure we received the end of headers. */
333
 
  if (header == NULL)
 
360
  if (header == NULL and http->response() == gearmand::protocol::httpd::HTTP_OK)
334
361
  {
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;
342
369
 
343
 
  if (http->method() == gearmand::protocol::HTTP::TRACE)
 
370
  if (http->response() != gearmand::protocol::httpd::HTTP_OK)
 
371
  {
 
372
    packet->command= GEARMAN_COMMAND_ECHO_REQ;
 
373
 
 
374
    *ret_ptr= gearmand_packet_pack_header(packet);
 
375
    if (*ret_ptr != GEARMAN_SUCCESS)
 
376
    {
 
377
      return 0;
 
378
    }
 
379
 
 
380
    packet->data_size= 0;
 
381
    packet->data= NULL;
 
382
  }
 
383
  else if (http->method() == gearmand::protocol::httpd::TRACE)
344
384
  {
345
385
    packet->command= GEARMAN_COMMAND_ECHO_REQ;
346
386
 
353
393
    packet->data_size= data_size;
354
394
    packet->data= (const char*)data;
355
395
  }
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)
357
397
  {
358
398
    packet->command= GEARMAN_COMMAND_ECHO_REQ;
359
399
 
435
475
 
436
476
HTTP::HTTP() :
437
477
  Plugin("HTTP"),
438
 
  _method(gearmand::protocol::HTTP::TRACE),
 
478
  _method(gearmand::protocol::httpd::TRACE),
439
479
  _background(false),
440
 
  _keep_alive(false)
 
480
  _keep_alive(false),
 
481
  _http_response(gearmand::protocol::httpd::HTTP_OK)
441
482
{
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.");
453
494
  return gearmand_port_add(gearmand, global_port.c_str(), _http_con_add);
454
495
}
455
496
 
 
497
void HTTP::reset()
 
498
{
 
499
  _background= false;
 
500
  _keep_alive= false;
 
501
  _method= httpd::TRACE;
 
502
  _http_response= gearmand::protocol::httpd::HTTP_OK;
 
503
}
 
504
 
456
505
} // namespace protocol
457
506
} // namespace gearmand
458
507