Http2Parser.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. #ifdef WITH_NGHTTP2
  2. #include "Http2Parser.h"
  3. static nghttp2_nv make_nv(const char* name, const char* value) {
  4. nghttp2_nv nv;
  5. nv.name = (uint8_t*)name;
  6. nv.value = (uint8_t*)value;
  7. nv.namelen = strlen(name);
  8. nv.valuelen = strlen(value);
  9. nv.flags = NGHTTP2_NV_FLAG_NONE;
  10. return nv;
  11. }
  12. static nghttp2_nv make_nv2(const char* name, const char* value,
  13. int namelen, int valuelen) {
  14. nghttp2_nv nv;
  15. nv.name = (uint8_t*)name;
  16. nv.value = (uint8_t*)value;
  17. nv.namelen = namelen; nv.valuelen = valuelen;
  18. nv.flags = NGHTTP2_NV_FLAG_NONE;
  19. return nv;
  20. }
  21. static void print_frame_hd(const nghttp2_frame_hd* hd) {
  22. printd("[frame] length=%d type=%x flags=%x stream_id=%d\n",
  23. (int)hd->length, (int)hd->type, (int)hd->flags, hd->stream_id);
  24. }
  25. static int on_header_callback(nghttp2_session *session,
  26. const nghttp2_frame *frame,
  27. const uint8_t *name, size_t namelen,
  28. const uint8_t *value, size_t valuelen,
  29. uint8_t flags, void *userdata);
  30. static int on_data_chunk_recv_callback(nghttp2_session *session,
  31. uint8_t flags, int32_t stream_id, const uint8_t *data,
  32. size_t len, void *userdata);
  33. static int on_frame_recv_callback(nghttp2_session *session,
  34. const nghttp2_frame *frame, void *userdata);
  35. /*
  36. static ssize_t data_source_read_callback(nghttp2_session *session,
  37. int32_t stream_id, uint8_t *buf, size_t length,
  38. uint32_t *data_flags, nghttp2_data_source *source, void *userdata);
  39. */
  40. Http2Parser::Http2Parser(http_session_type type) {
  41. if (cbs == NULL) {
  42. nghttp2_session_callbacks_new(&cbs);
  43. nghttp2_session_callbacks_set_on_header_callback(cbs, on_header_callback);
  44. nghttp2_session_callbacks_set_on_data_chunk_recv_callback(cbs, on_data_chunk_recv_callback);
  45. nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv_callback);
  46. }
  47. if (type == HTTP_CLIENT) {
  48. nghttp2_session_client_new(&session, cbs, this);
  49. state = H2_SEND_MAGIC;
  50. }
  51. else if (type == HTTP_SERVER) {
  52. nghttp2_session_server_new(&session, cbs, this);
  53. state = H2_WANT_RECV;
  54. }
  55. //nghttp2_session_set_user_data(session, this);
  56. submited = NULL;
  57. parsed = NULL;
  58. stream_id = -1;
  59. stream_closed = 0;
  60. nghttp2_settings_entry settings[] = {
  61. {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}
  62. };
  63. nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, settings, ARRAY_SIZE(settings));
  64. state = H2_SEND_SETTINGS;
  65. //nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL);
  66. //state = H2_SEND_PING;
  67. }
  68. Http2Parser::~Http2Parser() {
  69. if (session) {
  70. nghttp2_session_del(session);
  71. session = NULL;
  72. }
  73. }
  74. int Http2Parser::GetSendData(char** data, size_t* len) {
  75. // HTTP2_MAGIC,HTTP2_SETTINGS,HTTP2_HEADERS
  76. *len = nghttp2_session_mem_send(session, (const uint8_t**)data);
  77. printd("nghttp2_session_mem_send %d\n", *len);
  78. if (*len != 0) return *len;
  79. if (submited == NULL) return 0;
  80. // HTTP2_DATA
  81. if (state == H2_SEND_HEADERS) {
  82. void* content = submited->Content();
  83. int content_length = submited->ContentLength();
  84. // HTTP2 DATA framehd
  85. state = H2_SEND_DATA_FRAME_HD;
  86. http2_frame_hd framehd;
  87. framehd.length = content_length;
  88. framehd.type = HTTP2_DATA;
  89. framehd.flags = HTTP2_FLAG_END_STREAM;
  90. framehd.stream_id = stream_id;
  91. *data = (char*)frame_hdbuf;
  92. *len = HTTP2_FRAME_HDLEN;
  93. printd("HTTP2 SEND_DATA_FRAME_HD...\n");
  94. if (submited->ContentType() == APPLICATION_GRPC) {
  95. grpc_message_hd msghd;
  96. msghd.flags = 0;
  97. msghd.length = content_length;
  98. printd("grpc_message_hd: flags=%d length=%d\n", msghd.flags, msghd.length);
  99. if (type == HTTP_SERVER) {
  100. // grpc server send grpc-status in HTTP2 header frame
  101. framehd.flags = HTTP2_FLAG_NONE;
  102. /*
  103. // @test protobuf
  104. // message StringMessage {
  105. // string str = 1;
  106. // }
  107. int protobuf_taglen = 0;
  108. int tag = PROTOBUF_MAKE_TAG(1, WIRE_TYPE_LENGTH_DELIMITED);
  109. unsigned char* p = frame_hdbuf + HTTP2_FRAME_HDLEN + GRPC_MESSAGE_HDLEN;
  110. int bytes = varint_encode(tag, p);
  111. protobuf_taglen += bytes;
  112. p += bytes;
  113. bytes = varint_encode(content_length, p);
  114. protobuf_taglen += bytes;
  115. msghd.length += protobuf_taglen;
  116. framehd.length += protobuf_taglen;
  117. *len += protobuf_taglen;
  118. */
  119. }
  120. grpc_message_hd_pack(&msghd, frame_hdbuf + HTTP2_FRAME_HDLEN);
  121. framehd.length += GRPC_MESSAGE_HDLEN;
  122. *len += GRPC_MESSAGE_HDLEN;
  123. }
  124. http2_frame_hd_pack(&framehd, frame_hdbuf);
  125. }
  126. else if (state == H2_SEND_DATA_FRAME_HD) {
  127. // HTTP2 DATA
  128. void* content = submited->Content();
  129. int content_length = submited->ContentLength();
  130. if (content_length == 0) {
  131. // skip send_data
  132. goto send_done;
  133. }
  134. else {
  135. printd("HTTP2 SEND_DATA... content_length=%d\n", content_length);
  136. state = H2_SEND_DATA;
  137. *data = (char*)content;
  138. *len = content_length;
  139. }
  140. }
  141. else if (state == H2_SEND_DATA) {
  142. send_done:
  143. state = H2_SEND_DONE;
  144. if (submited->ContentType() == APPLICATION_GRPC) {
  145. if (type == HTTP_SERVER && stream_closed) {
  146. // grpc HEADERS grpc-status
  147. printd("grpc HEADERS grpc-status: 0\n");
  148. int flags = NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS;
  149. nghttp2_nv nv = make_nv("grpc-status", "0");
  150. nghttp2_submit_headers(session, flags, stream_id, NULL, &nv, 1, NULL);
  151. *len = nghttp2_session_mem_send(session, (const uint8_t**)data);
  152. }
  153. }
  154. }
  155. printd("GetSendData %d\n", *len);
  156. return *len;
  157. }
  158. int Http2Parser::FeedRecvData(const char* data, size_t len) {
  159. printd("nghttp2_session_mem_recv %d\n", len);
  160. state = H2_WANT_RECV;
  161. size_t ret = nghttp2_session_mem_recv(session, (const uint8_t*)data, len);
  162. if (ret != len) {
  163. error = ret;
  164. }
  165. return (int)ret;
  166. }
  167. int Http2Parser::SubmitRequest(HttpRequest* req) {
  168. submited = req;
  169. req->FillContentType();
  170. req->FillContentLength();
  171. if (req->ContentType() == APPLICATION_GRPC) {
  172. req->method = HTTP_POST;
  173. req->headers["te"] = "trailers";
  174. req->headers["user-agent"] = "grpc-c++/1.16.0 grpc-c/6.0.0 (linux; nghttp2; hw)";
  175. req->headers["accept-encoding"] = "identity";
  176. req->headers["grpc-accept-encoding"] = "identity";
  177. }
  178. std::vector<nghttp2_nv> nvs;
  179. char c_str[256] = {0};
  180. req->ParseUrl();
  181. nvs.push_back(make_nv(":method", http_method_str(req->method)));
  182. nvs.push_back(make_nv(":path", req->path.c_str()));
  183. nvs.push_back(make_nv(":scheme", req->scheme.c_str()));
  184. if (req->port == 0 ||
  185. req->port == DEFAULT_HTTP_PORT ||
  186. req->port == DEFAULT_HTTPS_PORT) {
  187. nvs.push_back(make_nv(":authority", req->host.c_str()));
  188. }
  189. else {
  190. snprintf(c_str, sizeof(c_str), "%s:%d", req->host.c_str(), req->port);
  191. nvs.push_back(make_nv(":authority", c_str));
  192. }
  193. const char* name;
  194. const char* value;
  195. for (auto& header : req->headers) {
  196. name = header.first.c_str();
  197. value = header.second.c_str();
  198. hv_strlower((char*)name);
  199. if (strcmp(name, "host") == 0) {
  200. // :authority
  201. continue;
  202. }
  203. if (strcmp(name, "connection") == 0) {
  204. // HTTP2 default keep-alive
  205. continue;
  206. }
  207. if (strcmp(name, "content-length") == 0) {
  208. // HTTP2 have frame_hd.length
  209. continue;
  210. }
  211. nvs.push_back(make_nv2(name, value, header.first.size(), header.second.size()));
  212. }
  213. int flags = NGHTTP2_FLAG_END_HEADERS;
  214. // we set EOS on DATA frame
  215. stream_id = nghttp2_submit_headers(session, flags, -1, NULL, &nvs[0], nvs.size(), NULL);
  216. // avoid DATA_SOURCE_COPY, we do not use nghttp2_submit_data
  217. // nghttp2_data_provider data_prd;
  218. // data_prd.read_callback = data_source_read_callback;
  219. //stream_id = nghttp2_submit_request(session, NULL, &nvs[0], nvs.size(), &data_prd, NULL);
  220. state = H2_SEND_HEADERS;
  221. return 0;
  222. }
  223. int Http2Parser::SubmitResponse(HttpResponse* res) {
  224. submited = res;
  225. res->FillContentType();
  226. res->FillContentLength();
  227. if (parsed && parsed->ContentType() == APPLICATION_GRPC) {
  228. // correct content_type: application/grpc
  229. if (res->ContentType() != APPLICATION_GRPC) {
  230. res->content_type = APPLICATION_GRPC;
  231. res->headers["content-type"] = http_content_type_str(APPLICATION_GRPC);
  232. }
  233. //res->headers["accept-encoding"] = "identity";
  234. //res->headers["grpc-accept-encoding"] = "identity";
  235. //res->headers["grpc-status"] = "0";
  236. //res->status_code = HTTP_STATUS_OK;
  237. }
  238. std::vector<nghttp2_nv> nvs;
  239. char c_str[256] = {0};
  240. snprintf(c_str, sizeof(c_str), "%d", res->status_code);
  241. nvs.push_back(make_nv(":status", c_str));
  242. const char* name;
  243. const char* value;
  244. for (auto& header : res->headers) {
  245. name = header.first.c_str();
  246. value = header.second.c_str();
  247. hv_strlower((char*)name);
  248. if (strcmp(name, "connection") == 0) {
  249. // HTTP2 default keep-alive
  250. continue;
  251. }
  252. if (strcmp(name, "content-length") == 0) {
  253. // HTTP2 have frame_hd.length
  254. continue;
  255. }
  256. nvs.push_back(make_nv2(name, value, header.first.size(), header.second.size()));
  257. }
  258. int flags = NGHTTP2_FLAG_END_HEADERS;
  259. // we set EOS on DATA frame
  260. if (stream_id == -1) {
  261. // upgrade
  262. nghttp2_session_upgrade(session, NULL, 0, NULL);
  263. stream_id = 1;
  264. }
  265. nghttp2_submit_headers(session, flags, stream_id, NULL, &nvs[0], nvs.size(), NULL);
  266. // avoid DATA_SOURCE_COPY, we do not use nghttp2_submit_data
  267. // data_prd.read_callback = data_source_read_callback;
  268. //nghttp2_submit_response(session, stream_id, &nvs[0], nvs.size(), &data_prd);
  269. state = H2_SEND_HEADERS;
  270. return 0;
  271. }
  272. int Http2Parser::InitResponse(HttpResponse* res) {
  273. res->Reset();
  274. res->http_major = 2;
  275. res->http_minor = 0;
  276. parsed = res;
  277. return 0;
  278. }
  279. int Http2Parser::InitRequest(HttpRequest* req) {
  280. req->Reset();
  281. req->http_major = 2;
  282. req->http_minor = 0;
  283. parsed = req;
  284. return 0;
  285. }
  286. nghttp2_session_callbacks* Http2Parser::cbs = NULL;
  287. int on_header_callback(nghttp2_session *session,
  288. const nghttp2_frame *frame,
  289. const uint8_t *_name, size_t namelen,
  290. const uint8_t *_value, size_t valuelen,
  291. uint8_t flags, void *userdata) {
  292. printd("on_header_callback\n");
  293. print_frame_hd(&frame->hd);
  294. const char* name = (const char*)_name;
  295. const char* value = (const char*)_value;
  296. printd("%s: %s\n", name, value);
  297. Http2Parser* hp = (Http2Parser*)userdata;
  298. if (*name == ':') {
  299. if (hp->parsed->type == HTTP_REQUEST) {
  300. // :method :path :scheme :authority
  301. HttpRequest* req = (HttpRequest*)hp->parsed;
  302. if (strcmp(name, ":method") == 0) {
  303. req->method = http_method_enum(value);
  304. }
  305. else if (strcmp(name, ":path") == 0) {
  306. req->url = value;
  307. }
  308. else if (strcmp(name, ":scheme") == 0) {
  309. req->headers["Scheme"] = value;
  310. }
  311. else if (strcmp(name, ":authority") == 0) {
  312. req->headers["Host"] = value;
  313. }
  314. }
  315. else if (hp->parsed->type == HTTP_RESPONSE) {
  316. HttpResponse* res = (HttpResponse*)hp->parsed;
  317. if (strcmp(name, ":status") == 0) {
  318. res->status_code = (http_status)atoi(value);
  319. if (res->http_cb) {
  320. res->http_cb(res, HP_MESSAGE_BEGIN, NULL, 0);
  321. }
  322. }
  323. }
  324. }
  325. else {
  326. hp->parsed->headers[name] = value;
  327. if (strcmp(name, "content-type") == 0) {
  328. hp->parsed->content_type = http_content_type_enum(value);
  329. }
  330. }
  331. return 0;
  332. }
  333. int on_data_chunk_recv_callback(nghttp2_session *session,
  334. uint8_t flags, int32_t stream_id, const uint8_t *data,
  335. size_t len, void *userdata) {
  336. printd("on_data_chunk_recv_callback\n");
  337. printd("stream_id=%d length=%d\n", stream_id, (int)len);
  338. //printd("%.*s\n", (int)len, data);
  339. Http2Parser* hp = (Http2Parser*)userdata;
  340. if (hp->parsed->ContentType() == APPLICATION_GRPC) {
  341. // grpc_message_hd
  342. if (len >= GRPC_MESSAGE_HDLEN) {
  343. grpc_message_hd msghd;
  344. grpc_message_hd_unpack(&msghd, data);
  345. printd("grpc_message_hd: flags=%d length=%d\n", msghd.flags, msghd.length);
  346. data += GRPC_MESSAGE_HDLEN;
  347. len -= GRPC_MESSAGE_HDLEN;
  348. //printd("%.*s\n", (int)len, data);
  349. }
  350. }
  351. if (hp->parsed->http_cb) {
  352. hp->parsed->http_cb(hp->parsed, HP_BODY, (const char*)data, len);
  353. } else {
  354. hp->parsed->body.append((const char*)data, len);
  355. }
  356. return 0;
  357. }
  358. int on_frame_recv_callback(nghttp2_session *session,
  359. const nghttp2_frame *frame, void *userdata) {
  360. printd("on_frame_recv_callback\n");
  361. print_frame_hd(&frame->hd);
  362. Http2Parser* hp = (Http2Parser*)userdata;
  363. switch (frame->hd.type) {
  364. case NGHTTP2_DATA:
  365. hp->state = H2_RECV_DATA;
  366. break;
  367. case NGHTTP2_HEADERS:
  368. hp->state = H2_RECV_HEADERS;
  369. break;
  370. case NGHTTP2_SETTINGS:
  371. hp->state = H2_RECV_SETTINGS;
  372. break;
  373. case NGHTTP2_PING:
  374. hp->state = H2_RECV_PING;
  375. break;
  376. case NGHTTP2_RST_STREAM:
  377. case NGHTTP2_WINDOW_UPDATE:
  378. // ignore
  379. return 0;
  380. default:
  381. break;
  382. }
  383. if (hp->state == H2_RECV_HEADERS && hp->parsed->http_cb) {
  384. hp->parsed->http_cb(hp->parsed, HP_HEADERS_COMPLETE, NULL, 0);
  385. }
  386. if (frame->hd.stream_id >= hp->stream_id) {
  387. hp->stream_id = frame->hd.stream_id;
  388. hp->stream_closed = 0;
  389. if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
  390. printd("on_stream_closed stream_id=%d\n", hp->stream_id);
  391. hp->stream_closed = 1;
  392. hp->frame_type_when_stream_closed = frame->hd.type;
  393. if (hp->state == H2_RECV_HEADERS || hp->state == H2_RECV_DATA) {
  394. if (hp->parsed->http_cb) {
  395. hp->parsed->http_cb(hp->parsed, HP_MESSAGE_COMPLETE, NULL, 0);
  396. }
  397. }
  398. }
  399. }
  400. return 0;
  401. }
  402. #endif