php_http_parser.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560
  1. /* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include <assert.h>
  22. #include <stddef.h>
  23. #include "php_http_parser.h"
  24. #ifndef MIN
  25. # define MIN(a,b) ((a) < (b) ? (a) : (b))
  26. #endif
  27. #define CALLBACK2(FOR) \
  28. do { \
  29. if (settings->on_##FOR) { \
  30. if (0 != settings->on_##FOR(parser)) return (p - data); \
  31. } \
  32. } while (0)
  33. #define MARK(FOR) \
  34. do { \
  35. FOR##_mark = p; \
  36. } while (0)
  37. #define CALLBACK_NOCLEAR(FOR) \
  38. do { \
  39. if (FOR##_mark) { \
  40. if (settings->on_##FOR) { \
  41. if (0 != settings->on_##FOR(parser, \
  42. FOR##_mark, \
  43. p - FOR##_mark)) \
  44. { \
  45. return (p - data); \
  46. } \
  47. } \
  48. } \
  49. } while (0)
  50. #ifdef PHP_WIN32
  51. # undef CALLBACK
  52. #endif
  53. #define CALLBACK(FOR) \
  54. do { \
  55. CALLBACK_NOCLEAR(FOR); \
  56. FOR##_mark = NULL; \
  57. } while (0)
  58. #define PROXY_CONNECTION "proxy-connection"
  59. #define CONNECTION "connection"
  60. #define CONTENT_LENGTH "content-length"
  61. #define TRANSFER_ENCODING "transfer-encoding"
  62. #define UPGRADE "upgrade"
  63. #define CHUNKED "chunked"
  64. #define KEEP_ALIVE "keep-alive"
  65. #define CLOSE "close"
  66. static const char *method_strings[] =
  67. { "DELETE"
  68. , "GET"
  69. , "HEAD"
  70. , "POST"
  71. , "PUT"
  72. , "PATCH"
  73. , "CONNECT"
  74. , "OPTIONS"
  75. , "TRACE"
  76. , "COPY"
  77. , "LOCK"
  78. , "MKCOL"
  79. , "MOVE"
  80. , "MKCALENDAR"
  81. , "PROPFIND"
  82. , "PROPPATCH"
  83. , "SEARCH"
  84. , "UNLOCK"
  85. , "REPORT"
  86. , "MKACTIVITY"
  87. , "CHECKOUT"
  88. , "MERGE"
  89. , "M-SEARCH"
  90. , "NOTIFY"
  91. , "SUBSCRIBE"
  92. , "UNSUBSCRIBE"
  93. , "NOTIMPLEMENTED"
  94. };
  95. /* Tokens as defined by rfc 2616. Also lowercases them.
  96. * token = 1*<any CHAR except CTLs or separators>
  97. * separators = "(" | ")" | "<" | ">" | "@"
  98. * | "," | ";" | ":" | "\" | <">
  99. * | "/" | "[" | "]" | "?" | "="
  100. * | "{" | "}" | SP | HT
  101. */
  102. static const char tokens[256] = {
  103. /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
  104. 0, 0, 0, 0, 0, 0, 0, 0,
  105. /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
  106. 0, 0, 0, 0, 0, 0, 0, 0,
  107. /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
  108. 0, 0, 0, 0, 0, 0, 0, 0,
  109. /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
  110. 0, 0, 0, 0, 0, 0, 0, 0,
  111. /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
  112. ' ', '!', '"', '#', '$', '%', '&', '\'',
  113. /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
  114. 0, 0, '*', '+', 0, '-', '.', '/',
  115. /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
  116. '0', '1', '2', '3', '4', '5', '6', '7',
  117. /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
  118. '8', '9', 0, 0, 0, 0, 0, 0,
  119. /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
  120. 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
  121. /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
  122. 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
  123. /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
  124. 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
  125. /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
  126. 'x', 'y', 'z', 0, 0, 0, '^', '_',
  127. /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
  128. '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
  129. /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
  130. 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
  131. /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
  132. 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
  133. /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
  134. 'x', 'y', 'z', 0, '|', '}', '~', 0 };
  135. static const int8_t unhex[256] =
  136. {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  137. ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  138. ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  139. , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
  140. ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
  141. ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  142. ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
  143. ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  144. };
  145. static const uint8_t normal_url_char[256] = {
  146. /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
  147. 0, 0, 0, 0, 0, 0, 0, 0,
  148. /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
  149. 0, 0, 0, 0, 0, 0, 0, 0,
  150. /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
  151. 0, 0, 0, 0, 0, 0, 0, 0,
  152. /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
  153. 0, 0, 0, 0, 0, 0, 0, 0,
  154. /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
  155. 0, 1, 1, 0, 1, 1, 1, 1,
  156. /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
  157. 1, 1, 1, 1, 1, 1, 1, 1,
  158. /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
  159. 1, 1, 1, 1, 1, 1, 1, 1,
  160. /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
  161. 1, 1, 1, 1, 1, 1, 1, 0,
  162. /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
  163. 1, 1, 1, 1, 1, 1, 1, 1,
  164. /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
  165. 1, 1, 1, 1, 1, 1, 1, 1,
  166. /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
  167. 1, 1, 1, 1, 1, 1, 1, 1,
  168. /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
  169. 1, 1, 1, 1, 1, 1, 1, 1,
  170. /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
  171. 1, 1, 1, 1, 1, 1, 1, 1,
  172. /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
  173. 1, 1, 1, 1, 1, 1, 1, 1,
  174. /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
  175. 1, 1, 1, 1, 1, 1, 1, 1,
  176. /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
  177. 1, 1, 1, 1, 1, 1, 1, 0 };
  178. #define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
  179. enum header_states
  180. { h_general = 0
  181. , h_C
  182. , h_CO
  183. , h_CON
  184. , h_matching_connection
  185. , h_matching_proxy_connection
  186. , h_matching_content_length
  187. , h_matching_transfer_encoding
  188. , h_matching_upgrade
  189. , h_connection
  190. , h_content_length
  191. , h_transfer_encoding
  192. , h_upgrade
  193. , h_matching_transfer_encoding_chunked
  194. , h_matching_connection_keep_alive
  195. , h_matching_connection_close
  196. , h_transfer_encoding_chunked
  197. , h_connection_keep_alive
  198. , h_connection_close
  199. };
  200. enum flags
  201. { F_CHUNKED = 1 << 0
  202. , F_CONNECTION_KEEP_ALIVE = 1 << 1
  203. , F_CONNECTION_CLOSE = 1 << 2
  204. , F_TRAILING = 1 << 3
  205. , F_UPGRADE = 1 << 4
  206. , F_SKIPBODY = 1 << 5
  207. };
  208. #define CR '\r'
  209. #define LF '\n'
  210. #define LOWER(c) (unsigned char)(c | 0x20)
  211. #define TOKEN(c) tokens[(unsigned char)c]
  212. #define start_state (parser->type == PHP_HTTP_REQUEST ? s_start_req : s_start_res)
  213. #ifdef HTTP_PARSER_STRICT
  214. # define STRICT_CHECK(cond) if (cond) goto error
  215. # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
  216. #else
  217. # define STRICT_CHECK(cond)
  218. # define NEW_MESSAGE() start_state
  219. #endif
  220. size_t php_http_parser_execute (php_http_parser *parser,
  221. const php_http_parser_settings *settings,
  222. const char *data,
  223. size_t len)
  224. {
  225. char ch;
  226. signed char c;
  227. const char *p = data, *pe;
  228. size_t to_read;
  229. enum state state = (enum state) parser->state;
  230. enum header_states header_state = (enum header_states) parser->header_state;
  231. uint32_t index = parser->index;
  232. uint32_t nread = parser->nread;
  233. /* technically we could combine all of these (except for url_mark) into one
  234. variable, saving stack space, but it seems more clear to have them
  235. separated. */
  236. const char *header_field_mark = 0;
  237. const char *header_value_mark = 0;
  238. const char *fragment_mark = 0;
  239. const char *query_string_mark = 0;
  240. const char *path_mark = 0;
  241. const char *url_mark = 0;
  242. if (len == 0) {
  243. if (state == s_body_identity_eof) {
  244. CALLBACK2(message_complete);
  245. }
  246. return 0;
  247. }
  248. if (state == s_header_field)
  249. header_field_mark = data;
  250. if (state == s_header_value)
  251. header_value_mark = data;
  252. if (state == s_req_fragment)
  253. fragment_mark = data;
  254. if (state == s_req_query_string)
  255. query_string_mark = data;
  256. if (state == s_req_path)
  257. path_mark = data;
  258. if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash
  259. || state == s_req_schema_slash_slash || state == s_req_port
  260. || state == s_req_query_string_start || state == s_req_query_string
  261. || state == s_req_host
  262. || state == s_req_fragment_start || state == s_req_fragment)
  263. url_mark = data;
  264. for (p=data, pe=data+len; p != pe; p++) {
  265. ch = *p;
  266. if (PARSING_HEADER(state)) {
  267. ++nread;
  268. /* Buffer overflow attack */
  269. if (nread > PHP_HTTP_MAX_HEADER_SIZE) goto error;
  270. }
  271. switch (state) {
  272. case s_dead:
  273. /* this state is used after a 'Connection: close' message
  274. * the parser will error out if it reads another message
  275. */
  276. goto error;
  277. case s_start_req_or_res:
  278. {
  279. if (ch == CR || ch == LF)
  280. break;
  281. parser->flags = 0;
  282. parser->content_length = -1;
  283. CALLBACK2(message_begin);
  284. if (ch == 'H')
  285. state = s_res_or_resp_H;
  286. else {
  287. parser->type = PHP_HTTP_REQUEST;
  288. goto start_req_method_assign;
  289. }
  290. break;
  291. }
  292. case s_res_or_resp_H:
  293. if (ch == 'T') {
  294. parser->type = PHP_HTTP_RESPONSE;
  295. state = s_res_HT;
  296. } else {
  297. if (ch != 'E') goto error;
  298. parser->type = PHP_HTTP_REQUEST;
  299. parser->method = PHP_HTTP_HEAD;
  300. index = 2;
  301. state = s_req_method;
  302. }
  303. break;
  304. case s_start_res:
  305. {
  306. parser->flags = 0;
  307. parser->content_length = -1;
  308. CALLBACK2(message_begin);
  309. switch (ch) {
  310. case 'H':
  311. state = s_res_H;
  312. break;
  313. case CR:
  314. case LF:
  315. break;
  316. default:
  317. goto error;
  318. }
  319. break;
  320. }
  321. case s_res_H:
  322. STRICT_CHECK(ch != 'T');
  323. state = s_res_HT;
  324. break;
  325. case s_res_HT:
  326. STRICT_CHECK(ch != 'T');
  327. state = s_res_HTT;
  328. break;
  329. case s_res_HTT:
  330. STRICT_CHECK(ch != 'P');
  331. state = s_res_HTTP;
  332. break;
  333. case s_res_HTTP:
  334. STRICT_CHECK(ch != '/');
  335. state = s_res_first_http_major;
  336. break;
  337. case s_res_first_http_major:
  338. if (ch < '1' || ch > '9') goto error;
  339. parser->http_major = ch - '0';
  340. state = s_res_http_major;
  341. break;
  342. /* major HTTP version or dot */
  343. case s_res_http_major:
  344. {
  345. if (ch == '.') {
  346. state = s_res_first_http_minor;
  347. break;
  348. }
  349. if (ch < '0' || ch > '9') goto error;
  350. parser->http_major *= 10;
  351. parser->http_major += ch - '0';
  352. if (parser->http_major > 999) goto error;
  353. break;
  354. }
  355. /* first digit of minor HTTP version */
  356. case s_res_first_http_minor:
  357. if (ch < '0' || ch > '9') goto error;
  358. parser->http_minor = ch - '0';
  359. state = s_res_http_minor;
  360. break;
  361. /* minor HTTP version or end of request line */
  362. case s_res_http_minor:
  363. {
  364. if (ch == ' ') {
  365. state = s_res_first_status_code;
  366. break;
  367. }
  368. if (ch < '0' || ch > '9') goto error;
  369. parser->http_minor *= 10;
  370. parser->http_minor += ch - '0';
  371. if (parser->http_minor > 999) goto error;
  372. break;
  373. }
  374. case s_res_first_status_code:
  375. {
  376. if (ch < '0' || ch > '9') {
  377. if (ch == ' ') {
  378. break;
  379. }
  380. goto error;
  381. }
  382. parser->status_code = ch - '0';
  383. state = s_res_status_code;
  384. break;
  385. }
  386. case s_res_status_code:
  387. {
  388. if (ch < '0' || ch > '9') {
  389. switch (ch) {
  390. case ' ':
  391. state = s_res_status;
  392. break;
  393. case CR:
  394. state = s_res_line_almost_done;
  395. break;
  396. case LF:
  397. state = s_header_field_start;
  398. break;
  399. default:
  400. goto error;
  401. }
  402. break;
  403. }
  404. parser->status_code *= 10;
  405. parser->status_code += ch - '0';
  406. if (parser->status_code > 999) goto error;
  407. break;
  408. }
  409. case s_res_status:
  410. /* the human readable status. e.g. "NOT FOUND"
  411. * we are not humans so just ignore this */
  412. if (ch == CR) {
  413. state = s_res_line_almost_done;
  414. break;
  415. }
  416. if (ch == LF) {
  417. state = s_header_field_start;
  418. break;
  419. }
  420. break;
  421. case s_res_line_almost_done:
  422. STRICT_CHECK(ch != LF);
  423. state = s_header_field_start;
  424. break;
  425. case s_start_req:
  426. {
  427. if (ch == CR || ch == LF)
  428. break;
  429. parser->flags = 0;
  430. parser->content_length = -1;
  431. CALLBACK2(message_begin);
  432. if (ch < 'A' || 'Z' < ch) goto error;
  433. start_req_method_assign:
  434. parser->method = (enum php_http_method) 0;
  435. index = 1;
  436. switch (ch) {
  437. case 'C': parser->method = PHP_HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
  438. case 'D': parser->method = PHP_HTTP_DELETE; break;
  439. case 'G': parser->method = PHP_HTTP_GET; break;
  440. case 'H': parser->method = PHP_HTTP_HEAD; break;
  441. case 'L': parser->method = PHP_HTTP_LOCK; break;
  442. case 'M': parser->method = PHP_HTTP_MKCOL; /* or MOVE, MKCALENDAR, MKACTIVITY, MERGE, M-SEARCH */ break;
  443. case 'N': parser->method = PHP_HTTP_NOTIFY; break;
  444. case 'O': parser->method = PHP_HTTP_OPTIONS; break;
  445. case 'P': parser->method = PHP_HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break;
  446. case 'R': parser->method = PHP_HTTP_REPORT; break;
  447. case 'S': parser->method = PHP_HTTP_SUBSCRIBE; /* or SEARCH */ break;
  448. case 'T': parser->method = PHP_HTTP_TRACE; break;
  449. case 'U': parser->method = PHP_HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
  450. default: parser->method = PHP_HTTP_NOT_IMPLEMENTED; break;
  451. }
  452. state = s_req_method;
  453. break;
  454. }
  455. case s_req_method:
  456. {
  457. const char *matcher;
  458. if (ch == '\0')
  459. goto error;
  460. matcher = method_strings[parser->method];
  461. if (ch == ' ') {
  462. if (parser->method != PHP_HTTP_NOT_IMPLEMENTED && matcher[index] != '\0') {
  463. parser->method = PHP_HTTP_NOT_IMPLEMENTED;
  464. }
  465. state = s_req_spaces_before_url;
  466. } else if (parser->method == PHP_HTTP_NOT_IMPLEMENTED || ch == matcher[index]) {
  467. ; /* nada */
  468. } else if (parser->method == PHP_HTTP_CONNECT) {
  469. if (index == 1 && ch == 'H') {
  470. parser->method = PHP_HTTP_CHECKOUT;
  471. } else if (index == 2 && ch == 'P') {
  472. parser->method = PHP_HTTP_COPY;
  473. } else {
  474. parser->method = PHP_HTTP_NOT_IMPLEMENTED;
  475. }
  476. } else if (parser->method == PHP_HTTP_MKCOL) {
  477. if (index == 1 && ch == 'O') {
  478. parser->method = PHP_HTTP_MOVE;
  479. } else if (index == 3 && ch == 'A') {
  480. parser->method = PHP_HTTP_MKCALENDAR;
  481. } else if (index == 1 && ch == 'E') {
  482. parser->method = PHP_HTTP_MERGE;
  483. } else if (index == 1 && ch == '-') {
  484. parser->method = PHP_HTTP_MSEARCH;
  485. } else if (index == 2 && ch == 'A') {
  486. parser->method = PHP_HTTP_MKACTIVITY;
  487. } else {
  488. parser->method = PHP_HTTP_NOT_IMPLEMENTED;
  489. }
  490. } else if (index == 1 && parser->method == PHP_HTTP_POST && ch == 'R') {
  491. parser->method = PHP_HTTP_PROPFIND; /* or HTTP_PROPPATCH */
  492. } else if (index == 1 && parser->method == PHP_HTTP_POST && ch == 'U') {
  493. parser->method = PHP_HTTP_PUT;
  494. } else if (index == 1 && parser->method == PHP_HTTP_POST && ch == 'A') {
  495. parser->method = PHP_HTTP_PATCH;
  496. } else if (index == 1 && parser->method == PHP_HTTP_SUBSCRIBE && ch == 'E') {
  497. parser->method = PHP_HTTP_SEARCH;
  498. } else if (index == 2 && parser->method == PHP_HTTP_UNLOCK && ch == 'S') {
  499. parser->method = PHP_HTTP_UNSUBSCRIBE;
  500. } else if (index == 4 && parser->method == PHP_HTTP_PROPFIND && ch == 'P') {
  501. parser->method = PHP_HTTP_PROPPATCH;
  502. } else {
  503. parser->method = PHP_HTTP_NOT_IMPLEMENTED;
  504. }
  505. ++index;
  506. break;
  507. }
  508. case s_req_spaces_before_url:
  509. {
  510. if (ch == ' ') break;
  511. if (ch == '/' || ch == '*') {
  512. MARK(url);
  513. MARK(path);
  514. state = s_req_path;
  515. break;
  516. }
  517. c = LOWER(ch);
  518. if (c >= 'a' && c <= 'z') {
  519. MARK(url);
  520. state = s_req_schema;
  521. break;
  522. }
  523. goto error;
  524. }
  525. case s_req_schema:
  526. {
  527. c = LOWER(ch);
  528. if (c >= 'a' && c <= 'z') break;
  529. if (ch == ':') {
  530. state = s_req_schema_slash;
  531. break;
  532. } else if (ch == '.') {
  533. state = s_req_host;
  534. break;
  535. } else if ('0' <= ch && ch <= '9') {
  536. state = s_req_host;
  537. break;
  538. }
  539. goto error;
  540. }
  541. case s_req_schema_slash:
  542. STRICT_CHECK(ch != '/');
  543. state = s_req_schema_slash_slash;
  544. break;
  545. case s_req_schema_slash_slash:
  546. STRICT_CHECK(ch != '/');
  547. state = s_req_host;
  548. break;
  549. case s_req_host:
  550. {
  551. c = LOWER(ch);
  552. if (c >= 'a' && c <= 'z') break;
  553. if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break;
  554. switch (ch) {
  555. case ':':
  556. state = s_req_port;
  557. break;
  558. case '/':
  559. MARK(path);
  560. state = s_req_path;
  561. break;
  562. case ' ':
  563. /* The request line looks like:
  564. * "GET http://foo.bar.com HTTP/1.1"
  565. * That is, there is no path.
  566. */
  567. CALLBACK(url);
  568. state = s_req_http_start;
  569. break;
  570. default:
  571. goto error;
  572. }
  573. break;
  574. }
  575. case s_req_port:
  576. {
  577. if (ch >= '0' && ch <= '9') break;
  578. switch (ch) {
  579. case '/':
  580. MARK(path);
  581. state = s_req_path;
  582. break;
  583. case ' ':
  584. /* The request line looks like:
  585. * "GET http://foo.bar.com:1234 HTTP/1.1"
  586. * That is, there is no path.
  587. */
  588. CALLBACK(url);
  589. state = s_req_http_start;
  590. break;
  591. default:
  592. goto error;
  593. }
  594. break;
  595. }
  596. case s_req_path:
  597. {
  598. if (normal_url_char[(unsigned char)ch]) break;
  599. switch (ch) {
  600. case ' ':
  601. CALLBACK(url);
  602. CALLBACK(path);
  603. state = s_req_http_start;
  604. break;
  605. case CR:
  606. CALLBACK(url);
  607. CALLBACK(path);
  608. parser->http_major = 0;
  609. parser->http_minor = 9;
  610. state = s_req_line_almost_done;
  611. break;
  612. case LF:
  613. CALLBACK(url);
  614. CALLBACK(path);
  615. parser->http_major = 0;
  616. parser->http_minor = 9;
  617. state = s_header_field_start;
  618. break;
  619. case '?':
  620. CALLBACK(path);
  621. state = s_req_query_string_start;
  622. break;
  623. case '#':
  624. CALLBACK(path);
  625. state = s_req_fragment_start;
  626. break;
  627. default:
  628. goto error;
  629. }
  630. break;
  631. }
  632. case s_req_query_string_start:
  633. {
  634. if (normal_url_char[(unsigned char)ch]) {
  635. MARK(query_string);
  636. state = s_req_query_string;
  637. break;
  638. }
  639. switch (ch) {
  640. case '?':
  641. break; /* XXX ignore extra '?' ... is this right? */
  642. case ' ':
  643. CALLBACK(url);
  644. state = s_req_http_start;
  645. break;
  646. case CR:
  647. CALLBACK(url);
  648. parser->http_major = 0;
  649. parser->http_minor = 9;
  650. state = s_req_line_almost_done;
  651. break;
  652. case LF:
  653. CALLBACK(url);
  654. parser->http_major = 0;
  655. parser->http_minor = 9;
  656. state = s_header_field_start;
  657. break;
  658. case '#':
  659. state = s_req_fragment_start;
  660. break;
  661. default:
  662. goto error;
  663. }
  664. break;
  665. }
  666. case s_req_query_string:
  667. {
  668. if (normal_url_char[(unsigned char)ch]) break;
  669. switch (ch) {
  670. case '?':
  671. /* allow extra '?' in query string */
  672. break;
  673. case ' ':
  674. CALLBACK(url);
  675. CALLBACK(query_string);
  676. state = s_req_http_start;
  677. break;
  678. case CR:
  679. CALLBACK(url);
  680. CALLBACK(query_string);
  681. parser->http_major = 0;
  682. parser->http_minor = 9;
  683. state = s_req_line_almost_done;
  684. break;
  685. case LF:
  686. CALLBACK(url);
  687. CALLBACK(query_string);
  688. parser->http_major = 0;
  689. parser->http_minor = 9;
  690. state = s_header_field_start;
  691. break;
  692. case '#':
  693. CALLBACK(query_string);
  694. state = s_req_fragment_start;
  695. break;
  696. default:
  697. goto error;
  698. }
  699. break;
  700. }
  701. case s_req_fragment_start:
  702. {
  703. if (normal_url_char[(unsigned char)ch]) {
  704. MARK(fragment);
  705. state = s_req_fragment;
  706. break;
  707. }
  708. switch (ch) {
  709. case ' ':
  710. CALLBACK(url);
  711. state = s_req_http_start;
  712. break;
  713. case CR:
  714. CALLBACK(url);
  715. parser->http_major = 0;
  716. parser->http_minor = 9;
  717. state = s_req_line_almost_done;
  718. break;
  719. case LF:
  720. CALLBACK(url);
  721. parser->http_major = 0;
  722. parser->http_minor = 9;
  723. state = s_header_field_start;
  724. break;
  725. case '?':
  726. MARK(fragment);
  727. state = s_req_fragment;
  728. break;
  729. case '#':
  730. break;
  731. default:
  732. goto error;
  733. }
  734. break;
  735. }
  736. case s_req_fragment:
  737. {
  738. if (normal_url_char[(unsigned char)ch]) break;
  739. switch (ch) {
  740. case ' ':
  741. CALLBACK(url);
  742. CALLBACK(fragment);
  743. state = s_req_http_start;
  744. break;
  745. case CR:
  746. CALLBACK(url);
  747. CALLBACK(fragment);
  748. parser->http_major = 0;
  749. parser->http_minor = 9;
  750. state = s_req_line_almost_done;
  751. break;
  752. case LF:
  753. CALLBACK(url);
  754. CALLBACK(fragment);
  755. parser->http_major = 0;
  756. parser->http_minor = 9;
  757. state = s_header_field_start;
  758. break;
  759. case '?':
  760. case '#':
  761. break;
  762. default:
  763. goto error;
  764. }
  765. break;
  766. }
  767. case s_req_http_start:
  768. switch (ch) {
  769. case 'H':
  770. state = s_req_http_H;
  771. break;
  772. case ' ':
  773. break;
  774. default:
  775. goto error;
  776. }
  777. break;
  778. case s_req_http_H:
  779. STRICT_CHECK(ch != 'T');
  780. state = s_req_http_HT;
  781. break;
  782. case s_req_http_HT:
  783. STRICT_CHECK(ch != 'T');
  784. state = s_req_http_HTT;
  785. break;
  786. case s_req_http_HTT:
  787. STRICT_CHECK(ch != 'P');
  788. state = s_req_http_HTTP;
  789. break;
  790. case s_req_http_HTTP:
  791. STRICT_CHECK(ch != '/');
  792. state = s_req_first_http_major;
  793. break;
  794. /* first digit of major HTTP version */
  795. case s_req_first_http_major:
  796. if (ch < '1' || ch > '9') goto error;
  797. parser->http_major = ch - '0';
  798. state = s_req_http_major;
  799. break;
  800. /* major HTTP version or dot */
  801. case s_req_http_major:
  802. {
  803. if (ch == '.') {
  804. state = s_req_first_http_minor;
  805. break;
  806. }
  807. if (ch < '0' || ch > '9') goto error;
  808. parser->http_major *= 10;
  809. parser->http_major += ch - '0';
  810. if (parser->http_major > 999) goto error;
  811. break;
  812. }
  813. /* first digit of minor HTTP version */
  814. case s_req_first_http_minor:
  815. if (ch < '0' || ch > '9') goto error;
  816. parser->http_minor = ch - '0';
  817. state = s_req_http_minor;
  818. break;
  819. /* minor HTTP version or end of request line */
  820. case s_req_http_minor:
  821. {
  822. if (ch == CR) {
  823. state = s_req_line_almost_done;
  824. break;
  825. }
  826. if (ch == LF) {
  827. state = s_header_field_start;
  828. break;
  829. }
  830. /* XXX allow spaces after digit? */
  831. if (ch < '0' || ch > '9') goto error;
  832. parser->http_minor *= 10;
  833. parser->http_minor += ch - '0';
  834. if (parser->http_minor > 999) goto error;
  835. break;
  836. }
  837. /* end of request line */
  838. case s_req_line_almost_done:
  839. {
  840. if (ch != LF) goto error;
  841. state = s_header_field_start;
  842. break;
  843. }
  844. case s_header_field_start:
  845. {
  846. if (ch == CR) {
  847. state = s_headers_almost_done;
  848. break;
  849. }
  850. if (ch == LF) {
  851. /* they might be just sending \n instead of \r\n so this would be
  852. * the second \n to denote the end of headers*/
  853. state = s_headers_almost_done;
  854. goto headers_almost_done;
  855. }
  856. c = TOKEN(ch);
  857. if (!c) goto error;
  858. MARK(header_field);
  859. index = 0;
  860. state = s_header_field;
  861. switch (c) {
  862. case 'c':
  863. header_state = h_C;
  864. break;
  865. case 'p':
  866. header_state = h_matching_proxy_connection;
  867. break;
  868. case 't':
  869. header_state = h_matching_transfer_encoding;
  870. break;
  871. case 'u':
  872. header_state = h_matching_upgrade;
  873. break;
  874. default:
  875. header_state = h_general;
  876. break;
  877. }
  878. break;
  879. }
  880. case s_header_field:
  881. {
  882. c = TOKEN(ch);
  883. if (c) {
  884. switch (header_state) {
  885. case h_general:
  886. break;
  887. case h_C:
  888. index++;
  889. header_state = (c == 'o' ? h_CO : h_general);
  890. break;
  891. case h_CO:
  892. index++;
  893. header_state = (c == 'n' ? h_CON : h_general);
  894. break;
  895. case h_CON:
  896. index++;
  897. switch (c) {
  898. case 'n':
  899. header_state = h_matching_connection;
  900. break;
  901. case 't':
  902. header_state = h_matching_content_length;
  903. break;
  904. default:
  905. header_state = h_general;
  906. break;
  907. }
  908. break;
  909. /* connection */
  910. case h_matching_connection:
  911. index++;
  912. if (index > sizeof(CONNECTION)-1
  913. || c != CONNECTION[index]) {
  914. header_state = h_general;
  915. } else if (index == sizeof(CONNECTION)-2) {
  916. header_state = h_connection;
  917. }
  918. break;
  919. /* proxy-connection */
  920. case h_matching_proxy_connection:
  921. index++;
  922. if (index > sizeof(PROXY_CONNECTION)-1
  923. || c != PROXY_CONNECTION[index]) {
  924. header_state = h_general;
  925. } else if (index == sizeof(PROXY_CONNECTION)-2) {
  926. header_state = h_connection;
  927. }
  928. break;
  929. /* content-length */
  930. case h_matching_content_length:
  931. index++;
  932. if (index > sizeof(CONTENT_LENGTH)-1
  933. || c != CONTENT_LENGTH[index]) {
  934. header_state = h_general;
  935. } else if (index == sizeof(CONTENT_LENGTH)-2) {
  936. header_state = h_content_length;
  937. }
  938. break;
  939. /* transfer-encoding */
  940. case h_matching_transfer_encoding:
  941. index++;
  942. if (index > sizeof(TRANSFER_ENCODING)-1
  943. || c != TRANSFER_ENCODING[index]) {
  944. header_state = h_general;
  945. } else if (index == sizeof(TRANSFER_ENCODING)-2) {
  946. header_state = h_transfer_encoding;
  947. }
  948. break;
  949. /* upgrade */
  950. case h_matching_upgrade:
  951. index++;
  952. if (index > sizeof(UPGRADE)-1
  953. || c != UPGRADE[index]) {
  954. header_state = h_general;
  955. } else if (index == sizeof(UPGRADE)-2) {
  956. header_state = h_upgrade;
  957. }
  958. break;
  959. case h_connection:
  960. case h_content_length:
  961. case h_transfer_encoding:
  962. case h_upgrade:
  963. if (ch != ' ') header_state = h_general;
  964. break;
  965. default:
  966. assert(0 && "Unknown header_state");
  967. break;
  968. }
  969. break;
  970. }
  971. if (ch == ':') {
  972. CALLBACK(header_field);
  973. state = s_header_value_start;
  974. break;
  975. }
  976. if (ch == CR) {
  977. state = s_header_almost_done;
  978. CALLBACK(header_field);
  979. break;
  980. }
  981. if (ch == LF) {
  982. CALLBACK(header_field);
  983. state = s_header_field_start;
  984. break;
  985. }
  986. goto error;
  987. }
  988. case s_header_value_start:
  989. {
  990. if (ch == ' ') break;
  991. MARK(header_value);
  992. state = s_header_value;
  993. index = 0;
  994. c = LOWER(ch);
  995. if (ch == CR) {
  996. CALLBACK(header_value);
  997. header_state = h_general;
  998. state = s_header_almost_done;
  999. break;
  1000. }
  1001. if (ch == LF) {
  1002. CALLBACK(header_value);
  1003. state = s_header_field_start;
  1004. break;
  1005. }
  1006. switch (header_state) {
  1007. case h_upgrade:
  1008. parser->flags |= F_UPGRADE;
  1009. header_state = h_general;
  1010. break;
  1011. case h_transfer_encoding:
  1012. /* looking for 'Transfer-Encoding: chunked' */
  1013. if ('c' == c) {
  1014. header_state = h_matching_transfer_encoding_chunked;
  1015. } else {
  1016. header_state = h_general;
  1017. }
  1018. break;
  1019. case h_content_length:
  1020. if (ch < '0' || ch > '9') goto error;
  1021. parser->content_length = ch - '0';
  1022. break;
  1023. case h_connection:
  1024. /* looking for 'Connection: keep-alive' */
  1025. if (c == 'k') {
  1026. header_state = h_matching_connection_keep_alive;
  1027. /* looking for 'Connection: close' */
  1028. } else if (c == 'c') {
  1029. header_state = h_matching_connection_close;
  1030. } else {
  1031. header_state = h_general;
  1032. }
  1033. break;
  1034. default:
  1035. header_state = h_general;
  1036. break;
  1037. }
  1038. break;
  1039. }
  1040. case s_header_value:
  1041. {
  1042. c = LOWER(ch);
  1043. if (ch == CR) {
  1044. CALLBACK(header_value);
  1045. state = s_header_almost_done;
  1046. break;
  1047. }
  1048. if (ch == LF) {
  1049. CALLBACK(header_value);
  1050. goto header_almost_done;
  1051. }
  1052. switch (header_state) {
  1053. case h_general:
  1054. break;
  1055. case h_connection:
  1056. case h_transfer_encoding:
  1057. assert(0 && "Shouldn't get here.");
  1058. break;
  1059. case h_content_length:
  1060. if (ch == ' ') break;
  1061. if (ch < '0' || ch > '9') goto error;
  1062. parser->content_length *= 10;
  1063. parser->content_length += ch - '0';
  1064. break;
  1065. /* Transfer-Encoding: chunked */
  1066. case h_matching_transfer_encoding_chunked:
  1067. index++;
  1068. if (index > sizeof(CHUNKED)-1
  1069. || c != CHUNKED[index]) {
  1070. header_state = h_general;
  1071. } else if (index == sizeof(CHUNKED)-2) {
  1072. header_state = h_transfer_encoding_chunked;
  1073. }
  1074. break;
  1075. /* looking for 'Connection: keep-alive' */
  1076. case h_matching_connection_keep_alive:
  1077. index++;
  1078. if (index > sizeof(KEEP_ALIVE)-1
  1079. || c != KEEP_ALIVE[index]) {
  1080. header_state = h_general;
  1081. } else if (index == sizeof(KEEP_ALIVE)-2) {
  1082. header_state = h_connection_keep_alive;
  1083. }
  1084. break;
  1085. /* looking for 'Connection: close' */
  1086. case h_matching_connection_close:
  1087. index++;
  1088. if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) {
  1089. header_state = h_general;
  1090. } else if (index == sizeof(CLOSE)-2) {
  1091. header_state = h_connection_close;
  1092. }
  1093. break;
  1094. case h_transfer_encoding_chunked:
  1095. case h_connection_keep_alive:
  1096. case h_connection_close:
  1097. if (ch != ' ') header_state = h_general;
  1098. break;
  1099. default:
  1100. state = s_header_value;
  1101. header_state = h_general;
  1102. break;
  1103. }
  1104. break;
  1105. }
  1106. case s_header_almost_done:
  1107. header_almost_done:
  1108. {
  1109. STRICT_CHECK(ch != LF);
  1110. state = s_header_field_start;
  1111. switch (header_state) {
  1112. case h_connection_keep_alive:
  1113. parser->flags |= F_CONNECTION_KEEP_ALIVE;
  1114. break;
  1115. case h_connection_close:
  1116. parser->flags |= F_CONNECTION_CLOSE;
  1117. break;
  1118. case h_transfer_encoding_chunked:
  1119. parser->flags |= F_CHUNKED;
  1120. break;
  1121. default:
  1122. break;
  1123. }
  1124. break;
  1125. }
  1126. case s_headers_almost_done:
  1127. headers_almost_done:
  1128. {
  1129. STRICT_CHECK(ch != LF);
  1130. if (parser->flags & F_TRAILING) {
  1131. /* End of a chunked request */
  1132. CALLBACK2(message_complete);
  1133. state = NEW_MESSAGE();
  1134. break;
  1135. }
  1136. nread = 0;
  1137. if ((parser->flags & F_UPGRADE) || parser->method == PHP_HTTP_CONNECT) {
  1138. parser->upgrade = 1;
  1139. }
  1140. /* Here we call the headers_complete callback. This is somewhat
  1141. * different than other callbacks because if the user returns 1, we
  1142. * will interpret that as saying that this message has no body. This
  1143. * is needed for the annoying case of receiving a response to a HEAD
  1144. * request.
  1145. */
  1146. if (settings->on_headers_complete) {
  1147. switch (settings->on_headers_complete(parser)) {
  1148. case 0:
  1149. break;
  1150. case 1:
  1151. parser->flags |= F_SKIPBODY;
  1152. break;
  1153. default:
  1154. return p - data; /* Error */
  1155. }
  1156. }
  1157. /* We cannot meaningfully support upgrade requests, since we only
  1158. * support HTTP/1 for now.
  1159. */
  1160. #if 0
  1161. /* Exit, the rest of the connect is in a different protocol. */
  1162. if (parser->upgrade) {
  1163. CALLBACK2(message_complete);
  1164. return (p - data);
  1165. }
  1166. #endif
  1167. if (parser->flags & F_SKIPBODY) {
  1168. CALLBACK2(message_complete);
  1169. state = NEW_MESSAGE();
  1170. } else if (parser->flags & F_CHUNKED) {
  1171. /* chunked encoding - ignore Content-Length header */
  1172. state = s_chunk_size_start;
  1173. } else {
  1174. if (parser->content_length == 0) {
  1175. /* Content-Length header given but zero: Content-Length: 0\r\n */
  1176. CALLBACK2(message_complete);
  1177. state = NEW_MESSAGE();
  1178. } else if (parser->content_length > 0) {
  1179. /* Content-Length header given and non-zero */
  1180. state = s_body_identity;
  1181. } else {
  1182. if (parser->type == PHP_HTTP_REQUEST || php_http_should_keep_alive(parser)) {
  1183. /* Assume content-length 0 - read the next */
  1184. CALLBACK2(message_complete);
  1185. state = NEW_MESSAGE();
  1186. } else {
  1187. /* Read body until EOF */
  1188. state = s_body_identity_eof;
  1189. }
  1190. }
  1191. }
  1192. break;
  1193. }
  1194. case s_body_identity:
  1195. assert(pe >= p);
  1196. to_read = MIN((size_t)(pe - p), (size_t)parser->content_length);
  1197. if (to_read > 0) {
  1198. if (settings->on_body) settings->on_body(parser, p, to_read);
  1199. p += to_read - 1;
  1200. parser->content_length -= to_read;
  1201. if (parser->content_length == 0) {
  1202. CALLBACK2(message_complete);
  1203. state = NEW_MESSAGE();
  1204. }
  1205. }
  1206. break;
  1207. /* read until EOF */
  1208. case s_body_identity_eof:
  1209. to_read = pe - p;
  1210. if (to_read > 0) {
  1211. if (settings->on_body) settings->on_body(parser, p, to_read);
  1212. p += to_read - 1;
  1213. }
  1214. break;
  1215. case s_chunk_size_start:
  1216. {
  1217. assert(parser->flags & F_CHUNKED);
  1218. c = unhex[(unsigned char)ch];
  1219. if (c == -1) goto error;
  1220. parser->content_length = c;
  1221. state = s_chunk_size;
  1222. break;
  1223. }
  1224. case s_chunk_size:
  1225. {
  1226. assert(parser->flags & F_CHUNKED);
  1227. if (ch == CR) {
  1228. state = s_chunk_size_almost_done;
  1229. break;
  1230. }
  1231. c = unhex[(unsigned char)ch];
  1232. if (c == -1) {
  1233. if (ch == ';' || ch == ' ') {
  1234. state = s_chunk_parameters;
  1235. break;
  1236. }
  1237. goto error;
  1238. }
  1239. parser->content_length *= 16;
  1240. parser->content_length += c;
  1241. break;
  1242. }
  1243. case s_chunk_parameters:
  1244. {
  1245. assert(parser->flags & F_CHUNKED);
  1246. /* just ignore this shit. TODO check for overflow */
  1247. if (ch == CR) {
  1248. state = s_chunk_size_almost_done;
  1249. break;
  1250. }
  1251. break;
  1252. }
  1253. case s_chunk_size_almost_done:
  1254. {
  1255. assert(parser->flags & F_CHUNKED);
  1256. STRICT_CHECK(ch != LF);
  1257. if (parser->content_length == 0) {
  1258. parser->flags |= F_TRAILING;
  1259. state = s_header_field_start;
  1260. } else {
  1261. state = s_chunk_data;
  1262. }
  1263. break;
  1264. }
  1265. case s_chunk_data:
  1266. {
  1267. assert(parser->flags & F_CHUNKED);
  1268. assert(pe >= p);
  1269. to_read = MIN((size_t)(pe - p), (size_t)(parser->content_length));
  1270. if (to_read > 0) {
  1271. if (settings->on_body) settings->on_body(parser, p, to_read);
  1272. p += to_read - 1;
  1273. }
  1274. if (to_read == (size_t)parser->content_length) {
  1275. state = s_chunk_data_almost_done;
  1276. }
  1277. parser->content_length -= to_read;
  1278. break;
  1279. }
  1280. case s_chunk_data_almost_done:
  1281. assert(parser->flags & F_CHUNKED);
  1282. STRICT_CHECK(ch != CR);
  1283. state = s_chunk_data_done;
  1284. break;
  1285. case s_chunk_data_done:
  1286. assert(parser->flags & F_CHUNKED);
  1287. STRICT_CHECK(ch != LF);
  1288. state = s_chunk_size_start;
  1289. break;
  1290. default:
  1291. assert(0 && "unhandled state");
  1292. goto error;
  1293. }
  1294. }
  1295. CALLBACK_NOCLEAR(header_field);
  1296. CALLBACK_NOCLEAR(header_value);
  1297. CALLBACK_NOCLEAR(fragment);
  1298. CALLBACK_NOCLEAR(query_string);
  1299. CALLBACK_NOCLEAR(path);
  1300. CALLBACK_NOCLEAR(url);
  1301. parser->state = state;
  1302. parser->header_state = header_state;
  1303. parser->index = index;
  1304. parser->nread = nread;
  1305. return len;
  1306. error:
  1307. parser->state = s_dead;
  1308. return (p - data);
  1309. }
  1310. int
  1311. php_http_should_keep_alive (php_http_parser *parser)
  1312. {
  1313. if (parser->http_major > 0 && parser->http_minor > 0) {
  1314. /* HTTP/1.1 */
  1315. if (parser->flags & F_CONNECTION_CLOSE) {
  1316. return 0;
  1317. } else {
  1318. return 1;
  1319. }
  1320. } else {
  1321. /* HTTP/1.0 or earlier */
  1322. if (parser->flags & F_CONNECTION_KEEP_ALIVE) {
  1323. return 1;
  1324. } else {
  1325. return 0;
  1326. }
  1327. }
  1328. }
  1329. const char * php_http_method_str (enum php_http_method m)
  1330. {
  1331. return method_strings[m];
  1332. }
  1333. void
  1334. php_http_parser_init (php_http_parser *parser, enum php_http_parser_type t)
  1335. {
  1336. parser->type = t;
  1337. parser->state = (t == PHP_HTTP_REQUEST ? s_start_req : (t == PHP_HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
  1338. parser->nread = 0;
  1339. parser->upgrade = 0;
  1340. parser->flags = 0;
  1341. parser->method = 0;
  1342. }