protocol.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
  2. *
  3. * Gearmand client and server library.
  4. *
  5. * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
  6. * Copyright (C) 2008 Brian Aker, Eric Day
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions are
  11. * met:
  12. *
  13. * * Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. *
  16. * * Redistributions in binary form must reproduce the above
  17. * copyright notice, this list of conditions and the following disclaimer
  18. * in the documentation and/or other materials provided with the
  19. * distribution.
  20. *
  21. * * The names of its contributors may not be used to endorse or
  22. * promote products derived from this software without specific prior
  23. * written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  28. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  30. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  31. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  32. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  33. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  34. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  35. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. */
  38. /**
  39. * @file
  40. * @brief HTTP Protocol Definitions
  41. */
  42. #include <gear_config.h>
  43. #include <libgearman-server/common.h>
  44. #include <libgearman/strcommand.h>
  45. #include <cstdio>
  46. #include <cstdlib>
  47. #include <libgearman-server/plugins/protocol/http/protocol.h>
  48. /**
  49. * @addtogroup gearmand::protocol::HTTPatic Static HTTP Protocol Definitions
  50. * @ingroup gearman_protocol_http
  51. * @{
  52. */
  53. /**
  54. * Default values.
  55. */
  56. #define GEARMAND_PROTOCOL_HTTP_DEFAULT_PORT "8080"
  57. #ifdef __clang__
  58. #pragma clang diagnostic push
  59. #pragma clang diagnostic ignored "-Wold-style-cast"
  60. #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
  61. #elif defined(__GNUC__)
  62. #pragma GCC diagnostic push
  63. #pragma GCC diagnostic ignored "-Wold-style-cast"
  64. #if __GNUC__ >= 7
  65. #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
  66. #endif /* __GNUC__ >= 7 */
  67. #endif
  68. class HTTPtext;
  69. /* Protocol callback functions. */
  70. class HTTPtext : public gearmand::protocol::Context
  71. {
  72. public:
  73. HTTPtext() :
  74. _method(gearmand::protocol::httpd::TRACE),
  75. _sent_header(false),
  76. _background(false),
  77. _keep_alive(false),
  78. _http_response(gearmand::protocol::httpd::HTTP_OK)
  79. {
  80. }
  81. ~HTTPtext()
  82. { }
  83. void notify(gearman_server_con_st*)
  84. {
  85. gearmand_debug("HTTP connection disconnected");
  86. }
  87. size_t pack(const gearmand_packet_st *packet,
  88. gearman_server_con_st *connection,
  89. void *send_buffer, const size_t send_buffer_size,
  90. gearmand_error_t& ret_ptr)
  91. {
  92. switch (packet->command)
  93. {
  94. case GEARMAN_COMMAND_WORK_DATA:
  95. {
  96. for (const char *ptr= packet->data; ptr <= (packet->data +packet->data_size) -2; ptr++)
  97. {
  98. content.push_back(*ptr);
  99. }
  100. gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "HTTP gearmand_command_t: GEARMAN_COMMAND_WORK_DATA length:%" PRIu64, uint64_t(content.size()));
  101. ret_ptr= GEARMAND_IGNORE_PACKET;
  102. return 0;
  103. }
  104. default:
  105. case GEARMAN_COMMAND_TEXT:
  106. case GEARMAN_COMMAND_CAN_DO:
  107. case GEARMAN_COMMAND_CANT_DO:
  108. case GEARMAN_COMMAND_RESET_ABILITIES:
  109. case GEARMAN_COMMAND_PRE_SLEEP:
  110. case GEARMAN_COMMAND_UNUSED:
  111. case GEARMAN_COMMAND_NOOP:
  112. case GEARMAN_COMMAND_SUBMIT_JOB:
  113. case GEARMAN_COMMAND_GRAB_JOB:
  114. case GEARMAN_COMMAND_NO_JOB:
  115. case GEARMAN_COMMAND_JOB_ASSIGN:
  116. case GEARMAN_COMMAND_WORK_STATUS:
  117. case GEARMAN_COMMAND_GET_STATUS:
  118. case GEARMAN_COMMAND_ECHO_REQ:
  119. case GEARMAN_COMMAND_SUBMIT_JOB_BG:
  120. case GEARMAN_COMMAND_ERROR:
  121. case GEARMAN_COMMAND_STATUS_RES:
  122. case GEARMAN_COMMAND_SUBMIT_JOB_HIGH:
  123. case GEARMAN_COMMAND_SET_CLIENT_ID:
  124. case GEARMAN_COMMAND_CAN_DO_TIMEOUT:
  125. case GEARMAN_COMMAND_ALL_YOURS:
  126. case GEARMAN_COMMAND_WORK_EXCEPTION:
  127. case GEARMAN_COMMAND_OPTION_REQ:
  128. case GEARMAN_COMMAND_OPTION_RES:
  129. case GEARMAN_COMMAND_WORK_WARNING:
  130. case GEARMAN_COMMAND_GRAB_JOB_UNIQ:
  131. case GEARMAN_COMMAND_JOB_ASSIGN_UNIQ:
  132. case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG:
  133. case GEARMAN_COMMAND_SUBMIT_JOB_LOW:
  134. case GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG:
  135. case GEARMAN_COMMAND_SUBMIT_JOB_SCHED:
  136. case GEARMAN_COMMAND_SUBMIT_JOB_EPOCH:
  137. case GEARMAN_COMMAND_SUBMIT_REDUCE_JOB:
  138. case GEARMAN_COMMAND_SUBMIT_REDUCE_JOB_BACKGROUND:
  139. case GEARMAN_COMMAND_GRAB_JOB_ALL:
  140. case GEARMAN_COMMAND_JOB_ASSIGN_ALL:
  141. case GEARMAN_COMMAND_GET_STATUS_UNIQUE:
  142. case GEARMAN_COMMAND_STATUS_RES_UNIQUE:
  143. case GEARMAN_COMMAND_MAX:
  144. gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM,
  145. "Bad packet command: gearmand_command_t:%s",
  146. gearman_strcommand(packet->command));
  147. assert(0);
  148. case GEARMAN_COMMAND_WORK_FAIL:
  149. case GEARMAN_COMMAND_ECHO_RES:
  150. case GEARMAN_COMMAND_WORK_COMPLETE:
  151. {
  152. ret_ptr = GEARMAND_SUCCESS;
  153. }
  154. break;
  155. case GEARMAN_COMMAND_JOB_CREATED:
  156. {
  157. if(this->_background) {
  158. ret_ptr = GEARMAND_SUCCESS;
  159. } else {
  160. gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM,
  161. "Sending HTTP told to ignore packet: gearmand_command_t:%s",
  162. gearman_strcommand(packet->command));
  163. ret_ptr= GEARMAND_IGNORE_PACKET;
  164. return 0;
  165. }
  166. }
  167. }
  168. gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM,
  169. "Sending HTTP response: Content-length:%" PRIu64 " data_size:%" PRIu64 " gearmand_command_t:%s response:%s",
  170. uint64_t(content.size()),
  171. uint64_t(packet->data_size),
  172. gearman_strcommand(packet->command),
  173. gearmand::protocol::httpd::response(response()));
  174. size_t pack_size= 0;
  175. if (_sent_header == false)
  176. {
  177. if (response() != gearmand::protocol::httpd::HTTP_OK)
  178. {
  179. pack_size= (size_t)snprintf((char *)send_buffer, send_buffer_size,
  180. "HTTP/1.0 %u %s\r\n"
  181. "Server: Gearman/" PACKAGE_VERSION "\r\n"
  182. "Content-Length: 0\r\n"
  183. "\r\n",
  184. unsigned(response()), gearmand::protocol::httpd::response(response()));
  185. }
  186. else if (method() == gearmand::protocol::httpd::HEAD)
  187. {
  188. pack_size= (size_t)snprintf((char *)send_buffer, send_buffer_size,
  189. "HTTP/1.0 200 OK\r\n"
  190. "X-Gearman-Job-Handle: %.*s\r\n"
  191. "Content-Length: %" PRIu64 "\r\n"
  192. "Server: Gearman/" PACKAGE_VERSION "\r\n"
  193. "\r\n",
  194. packet->command == GEARMAN_COMMAND_JOB_CREATED ? (int)packet->arg_size[0] : (int)packet->arg_size[0] - 1,
  195. (const char *)packet->arg[0],
  196. (uint64_t)packet->data_size);
  197. }
  198. else if (method() == gearmand::protocol::httpd::TRACE)
  199. {
  200. pack_size= (size_t)snprintf((char *)send_buffer, send_buffer_size,
  201. "HTTP/1.0 200 OK\r\n"
  202. "Server: Gearman/" PACKAGE_VERSION "\r\n"
  203. "Connection: close\r\n"
  204. "Content-Type: message/http\r\n"
  205. "\r\n");
  206. }
  207. else if (method() == gearmand::protocol::httpd::POST)
  208. {
  209. pack_size= (size_t)snprintf((char *)send_buffer, send_buffer_size,
  210. "HTTP/1.0 200 OK\r\n"
  211. "X-Gearman-Job-Handle: %.*s\r\n"
  212. "X-Gearman-Command: %s\r\n"
  213. "Content-Length: %" PRIu64 "\r\n"
  214. "Server: Gearman/" PACKAGE_VERSION "\r\n"
  215. "\r\n",
  216. packet->command == GEARMAN_COMMAND_JOB_CREATED ? int(packet->arg_size[0]) : int(packet->arg_size[0] - 1),
  217. (const char *)packet->arg[0], // Job handle
  218. gearman_strcommand(packet->command),
  219. (uint64_t)packet->data_size); // Content-length
  220. }
  221. else
  222. {
  223. pack_size= (size_t)snprintf((char *)send_buffer, send_buffer_size,
  224. "HTTP/1.0 200 OK\r\n"
  225. "X-Gearman-Job-Handle: %.*s\r\n"
  226. "X-Gearman-Command: %s\r\n"
  227. "Content-Length: %" PRIu64 "\r\n"
  228. "Server: Gearman/" PACKAGE_VERSION "\r\n"
  229. "\r\n",
  230. packet->command == GEARMAN_COMMAND_JOB_CREATED ? int(packet->arg_size[0]) : int(packet->arg_size[0] - 1),
  231. (const char *)packet->arg[0],
  232. gearman_strcommand(packet->command),
  233. (uint64_t)packet->data_size); // Content-length
  234. }
  235. _sent_header= true;
  236. }
  237. if (pack_size > send_buffer_size)
  238. {
  239. gearmand_debug("Sending HTTP had to flush");
  240. ret_ptr= GEARMAND_FLUSH_DATA;
  241. return 0;
  242. }
  243. memcpy(send_buffer, &content[0], content.size());
  244. pack_size+= content.size();
  245. #if 0
  246. if (keep_alive() == false)
  247. #endif
  248. {
  249. gearman_io_set_option(&connection->con, GEARMAND_CON_CLOSE_AFTER_FLUSH, true);
  250. }
  251. ret_ptr= GEARMAND_SUCCESS;
  252. return pack_size;
  253. }
  254. size_t unpack(gearmand_packet_st *packet,
  255. gearman_server_con_st *, //connection
  256. const void *data, const size_t data_size,
  257. gearmand_error_t& ret_ptr)
  258. {
  259. const char *unique= "-";
  260. size_t unique_size= 1;
  261. gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_NORMAL;
  262. gearmand_info("Receiving HTTP response");
  263. /* Get the request line first. */
  264. size_t request_size;
  265. size_t offset= 0;
  266. const char *request= parse_line(data, data_size, request_size, offset);
  267. if (request == NULL or request_size == 0)
  268. {
  269. gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Zero length request made");
  270. ret_ptr= GEARMAND_IO_WAIT;
  271. return offset;
  272. }
  273. reset();
  274. /* Parse out the method, URI, and HTTP version from the request line. */
  275. const char *uri= (const char *)memchr(request, ' ', request_size);
  276. if (uri == NULL)
  277. {
  278. gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad request line: %.*s", (uint32_t)request_size, request);
  279. set_response(gearmand::protocol::httpd::HTTP_NOT_FOUND);
  280. ret_ptr= GEARMAND_INVALID_PACKET;
  281. return 0;
  282. }
  283. {
  284. const char *method_str= request;
  285. ptrdiff_t method_size= uri -request;
  286. if (method_size == 3 and
  287. strncmp(method_str, "GET", 3) == 0)
  288. {
  289. set_method(gearmand::protocol::httpd::GET);
  290. }
  291. else if (method_size == 3 and
  292. strncmp(method_str, "PUT", 3) == 0)
  293. {
  294. set_method(gearmand::protocol::httpd::PUT);
  295. }
  296. else if (method_size == 4 and
  297. strncmp(method_str, "POST", 4) == 0)
  298. {
  299. set_method(gearmand::protocol::httpd::POST);
  300. }
  301. else if (method_size == 4 and
  302. strncmp(method_str, "HEAD", 4) == 0)
  303. {
  304. set_method(gearmand::protocol::httpd::HEAD);
  305. }
  306. else if (method_size == 5 and
  307. strncmp(method_str, "TRACE", 5) == 0)
  308. {
  309. set_method(gearmand::protocol::httpd::TRACE);
  310. }
  311. else
  312. {
  313. gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad method: %.*s", (uint32_t)method_size, method_str);
  314. set_response(gearmand::protocol::httpd::HTTP_METHOD_NOT_ALLOWED);
  315. ret_ptr= GEARMAND_INVALID_PACKET;
  316. return 0;
  317. }
  318. }
  319. gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "HTTP METHOD: %s", str_method(method()));
  320. while (*uri == ' ')
  321. {
  322. uri++;
  323. }
  324. // Remove leading /
  325. while (*uri == '/')
  326. {
  327. uri++;
  328. }
  329. const char *version= (const char *)memchr(uri, ' ', request_size - (size_t)(uri - request));
  330. if (version == NULL)
  331. {
  332. gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad request line: %.*s",
  333. (uint32_t)request_size, request);
  334. ret_ptr= GEARMAND_INVALID_PACKET;
  335. return 0;
  336. }
  337. ptrdiff_t uri_size= version -uri;
  338. gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "HTTP URI: \"%.*s\"", (int)uri_size, uri);
  339. switch (method())
  340. {
  341. case gearmand::protocol::httpd::POST:
  342. case gearmand::protocol::httpd::PUT:
  343. case gearmand::protocol::httpd::GET:
  344. if (uri_size == 0)
  345. {
  346. gearmand_error("must give function name in URI");
  347. set_response(gearmand::protocol::httpd::HTTP_NOT_FOUND);
  348. }
  349. case gearmand::protocol::httpd::TRACE:
  350. case gearmand::protocol::httpd::HEAD:
  351. break;
  352. }
  353. while (*version == ' ')
  354. {
  355. version++;
  356. }
  357. size_t version_size= request_size - size_t(version - request);
  358. if (version_size == 8 and
  359. strncmp(version, "HTTP/1.1", 8) == 0)
  360. {
  361. set_keep_alive(true);
  362. }
  363. else if (version_size == 8 and
  364. strncmp(version, "HTTP/1.0", 8) == 0)
  365. { }
  366. else
  367. {
  368. gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad version: %.*s", (uint32_t)version_size, version);
  369. ret_ptr= GEARMAND_INVALID_PACKET;
  370. return 0;
  371. }
  372. /* Loop through all the headers looking for ones of interest. */
  373. const char *header;
  374. size_t header_size;
  375. while ((header= parse_line(data, data_size, header_size, offset)) != NULL)
  376. {
  377. if (header_size == 0)
  378. {
  379. break;
  380. }
  381. if (header_size > 16 and
  382. strncasecmp(header, "Content-Length: ", 16) == 0)
  383. {
  384. if (method() == gearmand::protocol::httpd::PUT or
  385. method() == gearmand::protocol::httpd::POST)
  386. {
  387. char content_length[11]; /* 11 bytes to fit max display length of uint32_t */
  388. snprintf(content_length, sizeof(content_length), "%.*s", (int)header_size - 16,
  389. header + 16);
  390. packet->data_size= size_t(atoi(content_length));
  391. }
  392. }
  393. else if (header_size == 22 and
  394. strncasecmp(header, "Connection: Keep-Alive", 22) == 0)
  395. {
  396. set_keep_alive(true);
  397. }
  398. else if (header_size > 18 and
  399. strncasecmp(header, "X-Gearman-Unique: ", 18) == 0)
  400. {
  401. unique= header + 18;
  402. unique_size= header_size -18;
  403. }
  404. else if (header_size == 26 and
  405. strncasecmp(header, "X-Gearman-Background: true", 26) == 0)
  406. {
  407. set_background(true);
  408. }
  409. else if (header_size == 24 and
  410. strncasecmp(header, "X-Gearman-Priority: high", 24) == 0)
  411. {
  412. priority= GEARMAN_JOB_PRIORITY_HIGH;
  413. }
  414. else if (header_size == 23 and
  415. strncasecmp(header, "X-Gearman-Priority: low", 23) == 0)
  416. {
  417. priority= GEARMAN_JOB_PRIORITY_LOW;
  418. }
  419. }
  420. /* Make sure we received the end of headers. */
  421. if (header == NULL and response() == gearmand::protocol::httpd::HTTP_OK)
  422. {
  423. gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "No headers were found");
  424. ret_ptr= GEARMAND_IO_WAIT;
  425. return 0;
  426. }
  427. /* Request and all headers complete, build a packet based on HTTP request. */
  428. packet->magic= GEARMAN_MAGIC_REQUEST;
  429. if (response() != gearmand::protocol::httpd::HTTP_OK)
  430. {
  431. packet->command= GEARMAN_COMMAND_ECHO_REQ;
  432. if ((ret_ptr= gearmand_packet_pack_header(packet)) != GEARMAND_SUCCESS)
  433. {
  434. return 0;
  435. }
  436. packet->data_size= 0;
  437. packet->data= NULL;
  438. }
  439. else if (method() == gearmand::protocol::httpd::TRACE)
  440. {
  441. packet->command= GEARMAN_COMMAND_ECHO_REQ;
  442. if ((ret_ptr= gearmand_packet_pack_header(packet)) != GEARMAND_SUCCESS)
  443. {
  444. return 0;
  445. }
  446. packet->data_size= data_size;
  447. packet->data= (const char*)data;
  448. }
  449. else if (method() == gearmand::protocol::httpd::HEAD and uri_size == 0)
  450. {
  451. packet->command= GEARMAN_COMMAND_ECHO_REQ;
  452. if ((ret_ptr= gearmand_packet_pack_header(packet)) != GEARMAND_SUCCESS)
  453. {
  454. return 0;
  455. }
  456. }
  457. else
  458. {
  459. if (background())
  460. {
  461. if (priority == GEARMAN_JOB_PRIORITY_NORMAL)
  462. {
  463. packet->command= GEARMAN_COMMAND_SUBMIT_JOB_BG;
  464. }
  465. else if (priority == GEARMAN_JOB_PRIORITY_HIGH)
  466. {
  467. packet->command= GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG;
  468. }
  469. else
  470. {
  471. packet->command= GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG;
  472. }
  473. }
  474. else
  475. {
  476. if (priority == GEARMAN_JOB_PRIORITY_NORMAL)
  477. {
  478. packet->command= GEARMAN_COMMAND_SUBMIT_JOB;
  479. }
  480. else if (priority == GEARMAN_JOB_PRIORITY_HIGH)
  481. {
  482. packet->command= GEARMAN_COMMAND_SUBMIT_JOB_HIGH;
  483. }
  484. else
  485. {
  486. packet->command= GEARMAN_COMMAND_SUBMIT_JOB_LOW;
  487. }
  488. }
  489. if ((ret_ptr= gearmand_packet_pack_header(packet)) != GEARMAND_SUCCESS)
  490. {
  491. return 0;
  492. }
  493. if ((ret_ptr= gearmand_packet_create(packet, uri, (size_t)uri_size +1)) != GEARMAND_SUCCESS)
  494. {
  495. return 0;
  496. }
  497. if ((ret_ptr= gearmand_packet_create(packet, unique, unique_size +1)) != GEARMAND_SUCCESS)
  498. {
  499. return 0;
  500. }
  501. /* Make sure function and unique are NULL terminated. */
  502. packet->arg[0][uri_size]= 0;
  503. packet->arg[1][unique_size]= 0;
  504. ret_ptr= GEARMAND_SUCCESS;
  505. }
  506. gearmand_info("Receiving HTTP response(finished)");
  507. return offset;
  508. }
  509. bool background()
  510. {
  511. return _background;
  512. }
  513. void set_background(bool arg)
  514. {
  515. _background= arg;
  516. }
  517. bool keep_alive()
  518. {
  519. return _keep_alive;
  520. }
  521. void set_keep_alive(bool arg)
  522. {
  523. _keep_alive= arg;
  524. }
  525. void set_response(gearmand::protocol::httpd::response_t arg)
  526. {
  527. _http_response= arg;
  528. }
  529. gearmand::protocol::httpd::response_t response() const
  530. {
  531. return _http_response;
  532. }
  533. gearmand::protocol::httpd::method_t method()
  534. {
  535. return _method;
  536. }
  537. void set_method(gearmand::protocol::httpd::method_t arg)
  538. {
  539. _method= arg;
  540. }
  541. void reset()
  542. {
  543. _sent_header= false;
  544. _background= false;
  545. _keep_alive= false;
  546. content.clear();
  547. _method= gearmand::protocol::httpd::TRACE;
  548. _http_response= gearmand::protocol::httpd::HTTP_OK;
  549. }
  550. const char *parse_line(const void *data, const size_t data_size,
  551. size_t& line_size, size_t& offset)
  552. {
  553. const char *start= (const char *)data +offset;
  554. const char *end= (const char *)memchr(start, '\n', data_size -offset);
  555. if (end == NULL)
  556. {
  557. return NULL;
  558. }
  559. offset+= size_t(end - start) +1;
  560. if (end != start && *(end - 1) == '\r')
  561. {
  562. end--;
  563. }
  564. line_size= size_t(end - start);
  565. return start;
  566. }
  567. private:
  568. gearmand::protocol::httpd::method_t _method;
  569. bool _sent_header;
  570. bool _background;
  571. bool _keep_alive;
  572. std::string global_port;
  573. gearmand::protocol::httpd::response_t _http_response;
  574. std::vector<char> content;
  575. };
  576. static gearmand_error_t _http_con_remove(gearman_server_con_st*)
  577. {
  578. return GEARMAND_SUCCESS;
  579. }
  580. static gearmand_error_t _http_con_add(gearman_server_con_st *connection)
  581. {
  582. gearmand_info("HTTP connection made");
  583. HTTPtext *http= new (std::nothrow) HTTPtext;
  584. if (http == NULL)
  585. {
  586. gearmand_error("new");
  587. return GEARMAND_MEMORY_ALLOCATION_FAILURE;
  588. }
  589. connection->set_protocol(http);
  590. return GEARMAND_SUCCESS;
  591. }
  592. namespace gearmand {
  593. namespace protocol {
  594. HTTP::HTTP() :
  595. Plugin("HTTP")
  596. {
  597. command_line_options().add_options()
  598. ("http-port", boost::program_options::value(&_port)->default_value(GEARMAND_PROTOCOL_HTTP_DEFAULT_PORT), "Port to listen on.");
  599. }
  600. HTTP::~HTTP()
  601. {
  602. }
  603. gearmand_error_t HTTP::start(gearmand_st *gearmand)
  604. {
  605. gearmand_info("Initializing HTTP");
  606. return gearmand_port_add(gearmand, _port.c_str(), _http_con_add, _http_con_remove);
  607. }
  608. } // namespace protocol
  609. } // namespace gearmand
  610. /** @} */
  611. #ifdef __clang__
  612. #pragma clang diagnostic pop
  613. #elif defined(__GNUC_)
  614. #pragma GCC diagnostic pop
  615. #endif