PageRenderTime 199ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/http/http_parser.rl

http://github.com/mozy/mordor
Unknown | 1008 lines | 850 code | 158 blank | 0 comment | 0 complexity | 16277134f083b4339dd0fe411492db71 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "mordor/pch.h"
  3. #include "mordor/http/parser.h"
  4. #include <locale>
  5. #include <sstream>
  6. #include <string>
  7. #include "mordor/version.h"
  8. namespace Mordor {
  9. // From uri.rl
  10. std::string unescape(const std::string& str, bool spaceAsPlus = false);
  11. namespace HTTP {
  12. static
  13. Version
  14. parseVersion(const char *str)
  15. {
  16. Version ver;
  17. ver.major = atoi(str + 5);
  18. ver.minor = atoi(strchr(str + 5, '.') + 1);
  19. return ver;
  20. }
  21. static boost::posix_time::time_input_facet rfc1123Facet_in("%a, %d %b %Y %H:%M:%S GMT",
  22. 1 /* starting refcount, so this never gets deleted */);
  23. static boost::posix_time::time_input_facet rfc850Facet_in("%A, %d-%b-%y %H:%M:%S GMT",
  24. 1 /* starting refcount, so this never gets deleted */);
  25. static boost::posix_time::time_input_facet ansiFacet_in("%a %b %e %H:%M:%S %Y",
  26. 1 /* starting refcount, so this never gets deleted */);
  27. boost::posix_time::ptime
  28. parseHttpDate(const char *str, size_t size)
  29. {
  30. boost::posix_time::ptime result;
  31. std::string val(str, size);
  32. #define ATTEMPT_WITH_FACET(facet) \
  33. { \
  34. std::istringstream is(val); \
  35. is.imbue(std::locale(is.getloc(), facet)); \
  36. is >> result; \
  37. if (!result.is_not_a_date_time()) \
  38. return result; \
  39. }
  40. ATTEMPT_WITH_FACET(&rfc1123Facet_in);
  41. ATTEMPT_WITH_FACET(&rfc850Facet_in);
  42. ATTEMPT_WITH_FACET(&ansiFacet_in);
  43. return result;
  44. }
  45. static
  46. std::string
  47. unfold(char *p, char *pe)
  48. {
  49. char *start = p;
  50. char *pw = p;
  51. while (p < pe) {
  52. // Skip leading whitespace
  53. if (pw == start) {
  54. if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
  55. ++p; ++pw; ++start;
  56. continue;
  57. }
  58. }
  59. // Only copy if necessary
  60. if (pw != p) {
  61. *pw = *p;
  62. }
  63. ++p; ++pw;
  64. }
  65. // Remove trailing whitespace
  66. do {
  67. --pw;
  68. } while ((*pw == ' ' || *pw == '\t' || *pw == '\r' || *pw == '\n') && pw >= start);
  69. ++pw;
  70. return std::string(start, pw - start);
  71. }
  72. std::string
  73. unquote(const char *str, size_t size)
  74. {
  75. if (size == 0 || (str[0] != '"' && str[0] != '('))
  76. return std::string(str, size);
  77. MORDOR_ASSERT((str[size - 1] == '"' && str[0] == '"') ||
  78. (str[size - 1] == ')' && str[0] == '('));
  79. std::string result(str + 1, size - 2);
  80. char *p = const_cast<char *>(result.c_str());
  81. char *pe = p + result.size();
  82. char *pw = p;
  83. bool escaping = false;
  84. while (p < pe) {
  85. if (escaping) {
  86. escaping = false;
  87. } else if (*p == '\\') {
  88. escaping = true;
  89. ++p;
  90. continue;
  91. }
  92. // Only copy if necessary
  93. if (pw != p)
  94. *pw = *p;
  95. ++p; ++pw;
  96. }
  97. result.resize(pw - result.c_str());
  98. return result;
  99. }
  100. std::string
  101. unquote(const std::string &str)
  102. {
  103. if (str.empty() || (str[0] != '"' && str[0] != '('))
  104. return str;
  105. return unquote(str.c_str(), str.size());
  106. }
  107. %%{
  108. machine http_parser;
  109. # See RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616.html
  110. action mark { mark = fpc; }
  111. action mark2 { mark2 = fpc; }
  112. action clearmark2 { mark2 = NULL; }
  113. action done { fbreak; }
  114. action bad_header { if (m_strict) m_isBadValue = true; }
  115. prepush { prepush(); }
  116. postpop { postpop(); }
  117. # basic character types
  118. OCTET = any;
  119. CHAR = ascii;
  120. UPALPHA = "A".."Z";
  121. LOALPHA = "a".."z";
  122. ALPHA = alpha;
  123. DIGIT = digit;
  124. CTL = cntrl | 127;
  125. CR = "\r";
  126. LF = "\n";
  127. SP = " ";
  128. HT = "\t";
  129. # almost-basic character types
  130. # note that we allow a single LF for a CR LF
  131. CRLF = CR LF | LF;
  132. LWS = CRLF? ( SP | HT )+;
  133. TEXT = LWS | (OCTET -- CTL);
  134. HEX = xdigit;
  135. # some basic tokens
  136. separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT;
  137. token = (CHAR -- (separators | CTL))+;
  138. # token68 is from http://tools.ietf.org/html/draft-ietf-httpbis-p7-auth-26
  139. # token68 represents a set of 68 chars, we add ":" to support AWS and "@", "'" to support email address
  140. token68 = (ALPHA | DIGIT | "-" | "." | "_" | "~" | "+" | "/" | ":" | "@" | "'")+ "="*;
  141. quoted_pair = "\\" CHAR;
  142. ctext = TEXT -- ("(" | ")");
  143. comment = "(" @{fcall parse_comment;};
  144. parse_comment := (ctext | quoted_pair | '(' @{fcall parse_comment;} )* ")" @{fret;};
  145. qdtext = TEXT -- ("\"" | "\\");
  146. quoted_string = "\"" ( qdtext | quoted_pair )* "\"";
  147. base64char = ALPHA | DIGIT | '+' | '/';
  148. base64 = (base64char{4})+ ( (base64char{3} '=') | (base64char{2} '==') )?;
  149. action parse_HTTP_Version {
  150. MORDOR_ASSERT(m_ver);
  151. *m_ver = parseVersion(mark);
  152. mark = NULL;
  153. }
  154. HTTP_Version = ("HTTP/" DIGIT+ "." DIGIT+) >mark %parse_HTTP_Version;
  155. action save_date {
  156. MORDOR_ASSERT(m_date);
  157. *m_date = parseHttpDate(mark, fpc - mark);
  158. mark = NULL;
  159. }
  160. wkday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun";
  161. weekday = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday";
  162. month = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec";
  163. date1 = DIGIT{2} SP month SP DIGIT{4};
  164. date2 = DIGIT{2} "-" month "-" DIGIT{2};
  165. date3 = month SP ( DIGIT{2} | (SP DIGIT));
  166. time = DIGIT{2} ":" DIGIT{2} ":" DIGIT{2};
  167. rfc1123_date = wkday "," SP date1 SP time SP "GMT";
  168. rfc850_date = weekday "," SP date2 SP time SP "GMT";
  169. asctime_date = wkday SP date3 SP time SP DIGIT{4};
  170. HTTP_date = (rfc1123_date | rfc850_date | asctime_date) >mark %save_date;
  171. delta_seconds = DIGIT+;
  172. action save_product_name {
  173. m_product.product = std::string(mark, fpc - mark);
  174. mark = NULL;
  175. }
  176. action save_product_version {
  177. m_product.version = std::string(mark, fpc - mark);
  178. mark = NULL;
  179. }
  180. action save_product {
  181. MORDOR_ASSERT(m_productAndCommentList);
  182. m_productAndCommentList->push_back(m_product);
  183. m_product = Product();
  184. }
  185. action save_comment {
  186. MORDOR_ASSERT(m_productAndCommentList);
  187. m_productAndCommentList->push_back(unquote(mark, fpc - mark));
  188. mark = NULL;
  189. }
  190. product_version = token;
  191. product = token >mark %save_product_name ("/" product_version >mark %save_product_version)?;
  192. product_or_comment = (product %save_product) | (comment >mark %save_comment);
  193. product_and_comment_list = LWS* product_or_comment ( LWS+ product_or_comment)* LWS*;
  194. qvalue = ('0' ('.' DIGIT{0,3})?) | ('1' ('.' '0'{0,3})?);
  195. subtag = ALPHA{1,8};
  196. primary_tag = ALPHA{1,8};
  197. language_tag = primary_tag ("-" subtag);
  198. action start_etag {
  199. MORDOR_ASSERT(m_eTag);
  200. m_eTag->weak = false;
  201. }
  202. action save_weak {
  203. MORDOR_ASSERT(m_eTag);
  204. m_eTag->unspecified = false;
  205. m_eTag->weak = true;
  206. }
  207. action save_etag {
  208. MORDOR_ASSERT(m_eTag);
  209. m_eTag->unspecified = false;
  210. m_eTag->value = unquote(mark, fpc - mark);
  211. }
  212. action set_etag_list {
  213. m_eTag = &m_tempETag;
  214. }
  215. action save_unspecified {
  216. MORDOR_ASSERT(m_eTagSet);
  217. m_eTagSet->insert(ETag());
  218. }
  219. action save_etag_element {
  220. MORDOR_ASSERT(m_eTagSet);
  221. MORDOR_ASSERT(m_eTag == & m_tempETag);
  222. m_eTagSet->insert(m_tempETag);
  223. }
  224. weak = "W" "/" >save_weak;
  225. opaque_tag = quoted_string >mark %save_etag;
  226. entity_tag = ((weak)? opaque_tag) >start_etag;
  227. etag_list = LWS* ("*" % save_unspecified | (LWS* entity_tag %save_etag_element ( LWS* ',' LWS* entity_tag %save_etag_element)* LWS*) LWS* ) > set_etag_list;
  228. bytes_unit = "bytes";
  229. other_range_unit = token;
  230. range_unit = bytes_unit | other_range_unit;
  231. action save_field_name {
  232. m_genericHeaderName = std::string(mark2, fpc - mark2);
  233. mark2 = NULL;
  234. }
  235. action save_field_value {
  236. if (!mark2) break;
  237. std::string fieldValue = unfold((char*)mark2, (char*)fpc);
  238. if (m_isBadValue) {
  239. MORDOR_THROW_EXCEPTION(BadFieldValueException(m_genericHeaderName, fieldValue));
  240. m_isBadValue = false;
  241. fbreak;
  242. }
  243. StringMap::iterator it = m_entity->extension.find(m_genericHeaderName);
  244. if (it == m_entity->extension.end()) {
  245. m_entity->extension[m_genericHeaderName] = fieldValue;
  246. } else {
  247. it->second.append(",");
  248. it->second.append(fieldValue);
  249. }
  250. mark2 = NULL;
  251. }
  252. field_chars = OCTET -- (CTL | CR LF SP HT);
  253. field_name = token >mark2 %save_field_name;
  254. field_value = TEXT* >mark2 %save_field_value;
  255. message_header = field_name ":" field_value;
  256. action save_string {
  257. *m_string = std::string(mark, fpc - mark);
  258. mark = NULL;
  259. }
  260. action save_ulong {
  261. *m_ulong = strtoull(mark, NULL, 10);
  262. mark = NULL;
  263. }
  264. action save_element {
  265. MORDOR_ASSERT(m_list || m_set);
  266. if (m_list)
  267. m_list->push_back(std::string(mark, fpc - mark));
  268. else
  269. m_set->insert(std::string(mark, fpc - mark));
  270. mark = NULL;
  271. }
  272. element = token >mark %save_element;
  273. list = (LWS* element ( LWS* ',' LWS* element)* LWS*);
  274. action save_parameterized_list_element {
  275. ValueWithParameters vp;
  276. vp.value = std::string(mark, fpc - mark);
  277. m_parameterizedList->push_back(vp);
  278. m_parameters = &m_parameterizedList->back().parameters;
  279. mark = NULL;
  280. }
  281. action save_parameter_attribute {
  282. m_temp1 = std::string(mark, fpc - mark);
  283. // Don't NULL out here; could be base64 later
  284. }
  285. action save_parameter_attribute_unquote {
  286. m_temp1 = unquote(mark, fpc - mark);
  287. // Don't NULL out here; could be base64 later
  288. }
  289. action save_parameter_value {
  290. (*m_parameters)[m_temp1] = unquote(mark, fpc - mark);
  291. mark = NULL;
  292. }
  293. attribute = (token - 'q'i) >mark %save_parameter_attribute; # q separates params from accept-params
  294. value = (token | quoted_string) >mark %save_parameter_value;
  295. parameter = attribute '=' value;
  296. parameterizedListElement = token >mark %save_parameterized_list_element (';' parameter)*;
  297. parameterizedList = LWS* parameterizedListElement ( LWS* ',' LWS* parameterizedListElement)* LWS*;
  298. action save_auth_scheme {
  299. if (m_challengeList && ((!m_challengeList->empty() && m_auth == &m_challengeList->back())
  300. || m_challengeList->empty())) {
  301. AuthParams ap;
  302. m_challengeList->push_back(ap);
  303. m_auth = &m_challengeList->back();
  304. }
  305. m_auth->scheme = std::string(mark, fpc - mark);
  306. m_parameters = &m_auth->parameters;
  307. mark = NULL;
  308. }
  309. action save_token_param {
  310. m_auth->param = std::string(mark, fpc - mark);
  311. mark = NULL;
  312. }
  313. auth_param = attribute '=' value;
  314. auth_scheme = token;
  315. auth_params = auth_param (LWS* ',' LWS* auth_param)*;
  316. auth_token68 = token68 >mark %save_token_param;
  317. credentials = auth_scheme >mark %save_auth_scheme (SP+ (auth_token68 | auth_params))?;
  318. challenge = credentials;
  319. challengeList = LWS* challenge ( LWS* ',' LWS* challenge)* LWS*;
  320. action set_connection {
  321. m_set = &m_general->connection;
  322. m_list = NULL;
  323. }
  324. action set_date {
  325. m_date = &m_general->date;
  326. }
  327. action set_proxy_connection {
  328. m_set = &m_general->proxyConnection;
  329. m_list = NULL;
  330. }
  331. action set_trailer {
  332. m_set = &m_general->trailer;
  333. m_list = NULL;
  334. }
  335. action set_transfer_encoding {
  336. m_parameterizedList = &m_general->transferEncoding;
  337. }
  338. action save_upgrade_product {
  339. m_general->upgrade.push_back(m_product);
  340. m_product = Product();
  341. }
  342. Connection = 'Connection:'i @set_connection list;
  343. Date = 'Date:'i @set_date LWS* HTTP_date $lerr(bad_header) LWS*;
  344. # NON-STANDARD!!!
  345. Proxy_Connection = 'Proxy-Connection:'i @set_proxy_connection list;
  346. Trailer = 'Trailer:'i @set_trailer list;
  347. Transfer_Encoding = 'Transfer-Encoding:'i @set_transfer_encoding parameterizedList;
  348. Upgrade = 'Upgrade:'i LWS* product %save_upgrade_product ( LWS* ',' LWS* product %save_upgrade_product)* LWS*;
  349. general_header = Connection | Date | Proxy_Connection | Trailer | Transfer_Encoding | Upgrade;
  350. action set_allow {
  351. m_list = &m_entity->allow;
  352. m_set = NULL;
  353. }
  354. action set_content_encoding {
  355. m_list = &m_entity->contentEncoding;
  356. m_set = NULL;
  357. }
  358. action set_content_length {
  359. m_ulong = &m_entity->contentLength;
  360. }
  361. action set_content_md5 {
  362. m_string = &m_entity->contentMD5;
  363. }
  364. action save_cr_first_byte_pos {
  365. m_entity->contentRange.first = strtoull(mark, NULL, 10);
  366. mark = NULL;
  367. }
  368. action save_cr_last_byte_pos {
  369. m_entity->contentRange.last = strtoull(mark, NULL, 10);
  370. mark = NULL;
  371. }
  372. action save_blank_cr {
  373. m_entity->contentRange.last = 0;
  374. }
  375. action save_instance_length {
  376. m_entity->contentRange.instance = strtoull(mark, NULL, 10);
  377. mark = NULL;
  378. }
  379. action set_content_type
  380. {
  381. m_parameters = &m_entity->contentType.parameters;
  382. }
  383. action save_type
  384. {
  385. m_entity->contentType.type = std::string(mark, fpc - mark);
  386. mark = NULL;
  387. }
  388. action save_subtype
  389. {
  390. m_entity->contentType.subtype = std::string(mark, fpc - mark);
  391. mark = NULL;
  392. }
  393. action set_expires
  394. {
  395. m_date = &m_entity->expires;
  396. }
  397. action set_last_modified
  398. {
  399. m_date = &m_entity->lastModified;
  400. }
  401. Allow = 'Allow:'i @set_allow list;
  402. Content_Encoding = 'Content-Encoding:'i @set_content_encoding list;
  403. Content_Length = 'Content-Length:'i @set_content_length LWS* DIGIT+ >mark $lerr(bad_header) %save_ulong $lerr(bad_header) LWS*;
  404. Content_MD5 = 'Content-MD5:'i @set_content_md5 LWS* base64 >mark $lerr(bad_header) %save_string LWS*;
  405. byte_range_resp_spec = (DIGIT+ >mark %save_cr_first_byte_pos '-' DIGIT+ >mark %save_cr_last_byte_pos) | '*' %save_blank_cr;
  406. content_range_spec = bytes_unit SP byte_range_resp_spec '/' ( DIGIT+ >mark %save_instance_length | '*');
  407. Content_Range = 'Content-Range:'i LWS* content_range_spec $lerr(bad_header) LWS*;
  408. type = token >mark %save_type;
  409. subtype = token >mark %save_subtype;
  410. media_type = type '/' subtype (';' LWS* parameter)*;
  411. Content_Type = 'Content-Type:'i @set_content_type LWS* media_type LWS*;
  412. Expires = 'Expires:'i @set_expires LWS* HTTP_date $lerr(bad_header) LWS*;
  413. Last_Modified = 'Last-Modified:'i @set_last_modified LWS* HTTP_date $lerr(bad_header) LWS*;
  414. entity_header = Allow | Content_Encoding | Content_Length | Content_MD5 | Content_Range | Content_Type | Expires | Last_Modified; # | message_header;
  415. }%%
  416. %%{
  417. machine http_request_parser;
  418. include http_parser;
  419. include uri_parser "../uri.rl";
  420. action save_Method {
  421. m_request->requestLine.method = std::string(mark, fpc - mark);
  422. mark = NULL;
  423. }
  424. action set_request_uri {
  425. m_uri = &m_request->requestLine.uri;
  426. m_segments = &m_uri->path.segments;
  427. m_authority = &m_uri->authority;
  428. }
  429. action save_accept_list_element {
  430. if (m_acceptList) {
  431. AcceptValue av;
  432. if (fpc - mark != 1 || *mark != '*')
  433. av.value = std::string(mark, fpc - mark);
  434. m_acceptList->push_back(av);
  435. mark = NULL;
  436. } else {
  437. MORDOR_ASSERT(m_acceptListWithParams);
  438. AcceptValueWithParameters avp;
  439. avp.value = std::string(mark, fpc - mark);
  440. m_acceptListWithParams->push_back(avp);
  441. m_parameters = &m_acceptListWithParams->back().parameters;
  442. mark = NULL;
  443. }
  444. }
  445. action save_qvalue {
  446. unsigned int *qvalue = NULL;
  447. if (m_acceptList) {
  448. qvalue = &m_acceptList->back().qvalue;
  449. } else {
  450. MORDOR_ASSERT(m_acceptListWithParams);
  451. qvalue = &m_acceptListWithParams->back().qvalue;
  452. }
  453. *qvalue = 0;
  454. size_t i = 0;
  455. unsigned int curPlace = 1000;
  456. for (; i < 5 && mark < fpc; ++i, ++mark) {
  457. if (i == 1)
  458. continue;
  459. unsigned int cur = *mark - '0';
  460. *qvalue += cur * curPlace;
  461. curPlace /= 10;
  462. }
  463. mark = NULL;
  464. }
  465. action set_accept_charset {
  466. m_acceptList = &m_request->request.acceptCharset;
  467. m_acceptListWithParams = NULL;
  468. }
  469. action set_accept_encoding {
  470. m_acceptList = &m_request->request.acceptEncoding;
  471. m_acceptListWithParams = NULL;
  472. }
  473. action set_authorization {
  474. m_challengeList = NULL;
  475. m_auth = &m_request->request.authorization;
  476. }
  477. action save_expectation {
  478. KeyValueWithParameters kvp;
  479. kvp.key = std::string(mark, fpc - mark);
  480. m_request->request.expect.push_back(kvp);
  481. mark = NULL;
  482. }
  483. action save_expectation_value {
  484. m_request->request.expect.back().value = unquote(mark, fpc - mark);
  485. mark = NULL;
  486. }
  487. action save_expectation_param {
  488. m_temp1 = std::string(mark, fpc - mark);
  489. m_request->request.expect.back().parameters[m_temp1] = "";
  490. mark = NULL;
  491. }
  492. action save_expectation_param_value {
  493. m_request->request.expect.back().parameters[m_temp1] = unquote(mark, fpc - mark);
  494. mark = NULL;
  495. }
  496. action set_host {
  497. m_string = &m_request->request.host;
  498. }
  499. action set_if_match {
  500. m_eTagSet = &m_request->request.ifMatch;
  501. }
  502. action set_if_modified_since {
  503. m_date = &m_request->request.ifModifiedSince;
  504. }
  505. action set_if_none_match {
  506. m_eTagSet = &m_request->request.ifNoneMatch;
  507. }
  508. action clear_if_range_entity_tag {
  509. m_eTag = NULL;
  510. }
  511. action set_if_range_entity_tag {
  512. if (!m_eTag) {
  513. m_request->request.ifRange = ETag();
  514. m_eTag = boost::get<ETag>(&m_request->request.ifRange);
  515. }
  516. }
  517. action set_if_range_http_date {
  518. m_request->request.ifRange = boost::posix_time::ptime();
  519. m_date = boost::get<boost::posix_time::ptime>(&m_request->request.ifRange);
  520. }
  521. action set_if_unmodified_since {
  522. m_date = &m_request->request.ifModifiedSince;
  523. }
  524. action set_proxy_authorization {
  525. m_challengeList = NULL;
  526. m_auth = &m_request->request.proxyAuthorization;
  527. }
  528. action save_first_byte_pos {
  529. m_request->request.range.push_back(RangeSet::value_type(
  530. strtoull(mark, NULL, 10), ~0ull));
  531. mark = NULL;
  532. }
  533. action save_last_byte_pos {
  534. if (mark != NULL) {
  535. m_request->request.range.back().second = strtoull(mark, NULL, 10);
  536. }
  537. mark = NULL;
  538. }
  539. action save_suffix_byte_pos {
  540. m_request->request.range.push_back(RangeSet::value_type(
  541. ~0ull, strtoull(mark, NULL, 10)));
  542. mark = NULL;
  543. }
  544. action set_referer {
  545. m_uri = &m_request->request.referer;
  546. m_segments = &m_uri->path.segments;
  547. m_authority = &m_uri->authority;
  548. }
  549. action save_accept_attribute {
  550. m_temp1 = std::string(mark, fpc - mark);
  551. m_acceptListWithParams->back().acceptParams[m_temp1] = "";
  552. mark = NULL;
  553. }
  554. action save_accept_value {
  555. m_acceptListWithParams->back().acceptParams[m_temp1] = unquote(mark, fpc - mark);
  556. mark = NULL;
  557. }
  558. action set_te {
  559. m_acceptList = NULL;
  560. m_acceptListWithParams = &m_request->request.te;
  561. }
  562. action set_user_agent {
  563. m_productAndCommentList = &m_request->request.userAgent;
  564. }
  565. acceptListElement = ( token | '*' ) >mark %save_accept_list_element (';q='i qvalue >mark %save_qvalue)?;
  566. acceptList = LWS* acceptListElement ( LWS* ',' LWS* acceptListElement)* LWS*;
  567. Accept_Charset = 'Accept-Charset:'i @set_accept_charset acceptList;
  568. Accept_Encoding = 'Accept-Encoding:'i @set_accept_encoding acceptList;
  569. Authorization = 'Authorization:'i @set_authorization LWS* credentials;
  570. expect_params = ';' token >mark %save_expectation_param ( '=' (token | quoted_string) >mark %save_expectation_param_value )?;
  571. expectation = token >mark %save_expectation ( '=' (token | quoted_string) >mark %save_expectation_value expect_params* )?;
  572. Expect = 'Expect:'i LWS* expectation ( LWS* ',' LWS* expectation )* LWS*;
  573. Host = 'Host:'i @set_host LWS* (host (':' port)?) >mark %save_string LWS*;
  574. If_Match = 'If-Match:'i @set_if_match etag_list;
  575. If_Modified_Since = 'If-Modified-Since:'i @set_if_modified_since LWS* HTTP_date LWS*;
  576. If_None_Match = 'If-None-Match:'i @set_if_none_match etag_list;
  577. weak_for_if_range = "W" "/" >set_if_range_entity_tag >save_weak;
  578. entity_tag_for_if_range = ((weak_for_if_range)? opaque_tag >set_if_range_entity_tag) >clear_if_range_entity_tag;
  579. If_Range = 'If-Range:'i LWS* (entity_tag_for_if_range | HTTP_date >set_if_range_http_date) LWS*;
  580. If_Unmodified_Since = 'If-Unmodified-Since:'i @set_if_unmodified_since LWS* HTTP_date LWS*;
  581. Proxy_Authorization = 'Proxy-Authorization:'i @set_proxy_authorization LWS* credentials;
  582. byte_range_spec = DIGIT+ >mark %save_first_byte_pos '-' (DIGIT+ >mark %save_last_byte_pos)?;
  583. suffix_byte_range_spec = '-' DIGIT+ > mark %save_suffix_byte_pos;
  584. byte_range_set = LWS* (byte_range_spec | suffix_byte_range_spec) ( LWS* ',' LWS* (byte_range_spec | suffix_byte_range_spec))* LWS*;
  585. ranges_specifier = bytes_unit '=' byte_range_set;
  586. Range = 'Range:'i LWS* ranges_specifier $lerr(bad_header);
  587. Referer = 'Referer:'i @set_referer LWS* (absolute_URI | relative_URI);
  588. accept_extension = ';' token >mark %save_accept_attribute ('=' (token | quoted_string) >mark %save_accept_value)?;
  589. accept_params = ';q='i qvalue >mark %save_qvalue (accept_extension)*;
  590. acceptListWithParamsElement = token >mark %save_accept_list_element (';' parameter)* (accept_params)?;
  591. acceptListWithParams = LWS* acceptListWithParamsElement ( LWS* ',' LWS* acceptListWithParamsElement)* LWS*;
  592. TE = 'TE:'i @set_te acceptListWithParams;
  593. User_Agent = 'User-Agent:'i @set_user_agent product_and_comment_list;
  594. request_header = Accept_Charset | Accept_Encoding | Authorization | Expect | Host | If_Match | If_Modified_Since | If_None_Match | If_Range | If_Unmodified_Since | Proxy_Authorization | Range | Referer | TE | User_Agent;
  595. Method = token >mark %save_Method;
  596. # we explicitly add query to path_absolute, because the URI spec changed from RFC 2396 to RFC 3986
  597. # with the query not being part of hier_part
  598. Request_URI = ( "*" | absolute_URI | (path_absolute ( "?" query )?));
  599. # HTTP specifies that a Request_URI may be an authority, but only for the
  600. # CONNECT method; enforce that, and by so doing remove the ambiguity that
  601. # an authority might be a scheme
  602. Connect_Line = 'CONNECT' %save_Method SP authority >set_request_uri SP HTTP_Version CRLF;
  603. Request_Line = (Method - 'CONNECT') SP Request_URI >set_request_uri SP HTTP_Version CRLF;
  604. Request = (Request_Line | Connect_Line) (((general_header | request_header | entity_header) %clearmark2 | message_header) CRLF)* CRLF @done;
  605. main := Request;
  606. write data;
  607. }%%
  608. void
  609. Parser::init()
  610. {
  611. m_string = NULL;
  612. m_set = NULL;
  613. m_list = NULL;
  614. m_parameterizedList = NULL;
  615. m_acceptList = NULL;
  616. m_acceptListWithParams = NULL;
  617. m_parameters = NULL;
  618. m_auth = NULL;
  619. m_challengeList = NULL;
  620. m_ulong = NULL;
  621. m_eTag = NULL;
  622. m_eTagSet = NULL;
  623. m_productAndCommentList = NULL;
  624. mark2 = NULL;
  625. m_isBadValue = false;
  626. RagelParser::init();
  627. }
  628. const char *
  629. Parser::earliestPointer() const
  630. {
  631. const char *parent = RagelParser::earliestPointer();
  632. if (mark2 && parent)
  633. return (std::min)(mark2, parent);
  634. if (mark2)
  635. return mark2;
  636. return parent;
  637. }
  638. void
  639. Parser::adjustPointers(ptrdiff_t offset)
  640. {
  641. if (mark2)
  642. mark2 += offset;
  643. RagelParser::adjustPointers(offset);
  644. }
  645. RequestParser::RequestParser(Request& request, bool strict)
  646. : Parser(strict),
  647. m_request(&request),
  648. m_ver(&request.requestLine.ver),
  649. m_segments(&request.requestLine.uri.path.segments),
  650. m_authority(&request.requestLine.uri.authority),
  651. m_general(&request.general),
  652. m_entity(&request.entity)
  653. {}
  654. void
  655. RequestParser::init()
  656. {
  657. Parser::init();
  658. %% write init;
  659. }
  660. bool
  661. RequestParser::final() const
  662. {
  663. return cs >= http_request_parser_first_final;
  664. }
  665. bool
  666. RequestParser::error() const
  667. {
  668. return cs == http_request_parser_error;
  669. }
  670. void
  671. RequestParser::exec()
  672. {
  673. #ifdef MSVC
  674. #pragma warning(push)
  675. #pragma warning(disable : 4244)
  676. #endif
  677. %% write exec;
  678. #ifdef MSVC
  679. #pragma warning(pop)
  680. #endif
  681. }
  682. %%{
  683. machine http_response_parser;
  684. include http_parser;
  685. include uri_parser "../uri.rl";
  686. action parse_Status_Code {
  687. m_response->status.status = (Status)atoi(mark);
  688. mark = NULL;
  689. }
  690. action parse_Reason_Phrase {
  691. m_response->status.reason = std::string(mark, fpc - mark);
  692. mark = NULL;
  693. }
  694. action set_accept_ranges
  695. {
  696. m_set = &m_response->response.acceptRanges;
  697. m_list = NULL;
  698. }
  699. action set_etag
  700. {
  701. m_eTag = &m_response->response.eTag;
  702. }
  703. action set_proxy_authenticate {
  704. m_challengeList = &m_response->response.proxyAuthenticate;
  705. }
  706. action set_retry_after_http_date {
  707. m_response->response.retryAfter = boost::posix_time::ptime();
  708. m_date = boost::get<boost::posix_time::ptime>(&m_response->response.retryAfter);
  709. }
  710. action set_retry_after_delta_seconds {
  711. m_response->response.retryAfter = ~0ull;
  712. m_ulong = boost::get<unsigned long long>(&m_response->response.retryAfter);
  713. }
  714. action set_server {
  715. m_productAndCommentList = &m_response->response.server;
  716. }
  717. action set_www_authenticate {
  718. m_challengeList = &m_response->response.wwwAuthenticate;
  719. }
  720. Accept_Ranges = 'Accept-Ranges:'i @set_accept_ranges list;
  721. ETag = 'ETag:'i @set_etag LWS* entity_tag;
  722. # This *should* be absolute_URI, but we're generous
  723. Location = 'Location:'i LWS* URI_reference LWS*;
  724. Proxy_Authenticate = 'Proxy-Authenticate:'i @set_proxy_authenticate challengeList;
  725. Retry_After = 'Retry-After:'i LWS* (HTTP_date %set_retry_after_http_date | delta_seconds >mark %set_retry_after_delta_seconds %save_ulong) LWS*;
  726. Server = 'Server:'i @set_server product_and_comment_list;
  727. WWW_Authenticate = 'WWW-Authenticate:'i @set_www_authenticate challengeList;
  728. response_header = Accept_Ranges | ETag | Location | Proxy_Authenticate | Retry_After | Server | WWW_Authenticate;
  729. Status_Code = DIGIT{3} > mark %parse_Status_Code;
  730. Reason_Phrase = (TEXT -- (CR | LF))* >mark %parse_Reason_Phrase;
  731. Status_Line = HTTP_Version SP Status_Code SP Reason_Phrase CRLF;
  732. Response = Status_Line (((general_header | response_header | entity_header) %clearmark2 | message_header) CRLF)* CRLF @done;
  733. main := Response;
  734. write data;
  735. }%%
  736. ResponseParser::ResponseParser(Response& response, bool strict)
  737. : Parser(strict),
  738. m_response(&response),
  739. m_ver(&response.status.ver),
  740. m_uri(&response.response.location),
  741. m_segments(&response.response.location.path.segments),
  742. m_authority(&response.response.location.authority),
  743. m_general(&response.general),
  744. m_entity(&response.entity)
  745. {}
  746. void
  747. ResponseParser::init()
  748. {
  749. Parser::init();
  750. %% write init;
  751. }
  752. bool
  753. ResponseParser::final() const
  754. {
  755. return cs >= http_response_parser_first_final;
  756. }
  757. bool
  758. ResponseParser::error() const
  759. {
  760. return cs == http_response_parser_error;
  761. }
  762. void
  763. ResponseParser::exec()
  764. {
  765. #ifdef MSVC
  766. #pragma warning(push)
  767. #pragma warning(disable : 4244)
  768. #endif
  769. %% write exec;
  770. #ifdef MSVC
  771. #pragma warning(pop)
  772. #endif
  773. }
  774. %%{
  775. machine http_trailer_parser;
  776. include http_parser;
  777. trailer = ((entity_header %clearmark2 | message_header) CRLF)*;
  778. main := trailer CRLF @done;
  779. write data;
  780. }%%
  781. TrailerParser::TrailerParser(EntityHeaders& entity, bool strict)
  782. : Parser(strict), m_entity(&entity)
  783. {}
  784. void
  785. TrailerParser::init()
  786. {
  787. Parser::init();
  788. %% write init;
  789. }
  790. bool
  791. TrailerParser::final() const
  792. {
  793. return cs >= http_trailer_parser_first_final;
  794. }
  795. bool
  796. TrailerParser::error() const
  797. {
  798. return cs == http_trailer_parser_error;
  799. }
  800. void
  801. TrailerParser::exec()
  802. {
  803. #ifdef MSVC
  804. #pragma warning(push)
  805. #pragma warning(disable : 4244)
  806. #endif
  807. %% write exec;
  808. #ifdef MSVC
  809. #pragma warning(pop)
  810. #endif
  811. }
  812. %%{
  813. machine http_list_parser;
  814. include http_parser;
  815. main := list;
  816. write data;
  817. }%%
  818. ListParser::ListParser(StringSet& stringSet)
  819. : m_set(&stringSet),
  820. m_list(NULL)
  821. {}
  822. void
  823. ListParser::init()
  824. {
  825. RagelParser::init();
  826. %% write init;
  827. }
  828. bool
  829. ListParser::final() const
  830. {
  831. return cs >= http_list_parser_first_final;
  832. }
  833. bool
  834. ListParser::error() const
  835. {
  836. return cs == http_list_parser_error;
  837. }
  838. void
  839. ListParser::exec()
  840. {
  841. #ifdef MSVC
  842. #pragma warning(push)
  843. #pragma warning(disable : 4244)
  844. #endif
  845. %% write exec;
  846. #ifdef MSVC
  847. #pragma warning(pop)
  848. #endif
  849. }
  850. }}