Http2Session.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #ifdef WITH_NGHTTP2
  2. #include "Http2Session.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;
  18. nv.valuelen = valuelen;
  19. nv.flags = NGHTTP2_NV_FLAG_NONE;
  20. return nv;
  21. }
  22. static void print_frame_hd(const nghttp2_frame_hd* hd) {
  23. printd("[frame] length=%d type=%x flags=%x stream_id=%d\n",
  24. (int)hd->length, (int)hd->type, (int)hd->flags, hd->stream_id);
  25. }
  26. static int on_header_callback(nghttp2_session *session,
  27. const nghttp2_frame *frame,
  28. const uint8_t *name, size_t namelen,
  29. const uint8_t *value, size_t valuelen,
  30. uint8_t flags, void *userdata);
  31. static int on_data_chunk_recv_callback(nghttp2_session *session,
  32. uint8_t flags, int32_t stream_id, const uint8_t *data,
  33. size_t len, void *userdata);
  34. static int on_frame_recv_callback(nghttp2_session *session,
  35. const nghttp2_frame *frame, void *userdata);
  36. /*
  37. static ssize_t data_source_read_callback(nghttp2_session *session,
  38. int32_t stream_id, uint8_t *buf, size_t length,
  39. uint32_t *data_flags, nghttp2_data_source *source, void *userdata);
  40. */
  41. Http2Session::Http2Session(http_session_type type) {
  42. this->type = type;
  43. if (cbs == NULL) {
  44. nghttp2_session_callbacks_new(&cbs);
  45. nghttp2_session_callbacks_set_on_header_callback(cbs, on_header_callback);
  46. nghttp2_session_callbacks_set_on_data_chunk_recv_callback(cbs, on_data_chunk_recv_callback);
  47. nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv_callback);
  48. }
  49. if (type == HTTP_CLIENT) {
  50. nghttp2_session_client_new(&session, cbs, NULL);
  51. state = HSS_SEND_MAGIC;
  52. }
  53. else if (type == HTTP_SERVER) {
  54. nghttp2_session_server_new(&session, cbs, NULL);
  55. state = HSS_SEND_SETTINGS;
  56. }
  57. nghttp2_session_set_user_data(session, this);
  58. submited = NULL;
  59. parsed = NULL;
  60. stream_id = -1;
  61. stream_closed = 0;
  62. nghttp2_settings_entry settings[] = {
  63. {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}
  64. };
  65. nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, settings, ARRAY_SIZE(settings));
  66. state = HSS_SEND_SETTINGS;
  67. }
  68. Http2Session::~Http2Session() {
  69. if (session) {
  70. nghttp2_session_del(session);
  71. session = NULL;
  72. }
  73. }
  74. int Http2Session::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 == HSS_SEND_HEADERS) {
  82. void* content = submited->Content();
  83. int content_length = submited->ContentLength();
  84. // HTTP2 DATA framehd
  85. state = HSS_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 DATA framehd-------------------\n");
  94. if (submited->ContentType() == APPLICATION_GRPC) {
  95. printd("grpc DATA framehd-----------------\n");
  96. if (type == HTTP_SERVER) {
  97. // grpc server send grpc_status in HTTP2 header frame
  98. framehd.flags = HTTP2_FLAG_NONE;
  99. }
  100. framehd.length += GRPC_MESSAGE_HDLEN;
  101. grpc_message_hd msghd;
  102. msghd.flags = 0;
  103. msghd.length = content_length;
  104. grpc_message_hd_pack(&msghd, frame_hdbuf + HTTP2_FRAME_HDLEN);
  105. *len = HTTP2_FRAME_HDLEN + GRPC_MESSAGE_HDLEN;
  106. }
  107. http2_frame_hd_pack(&framehd, frame_hdbuf);
  108. }
  109. else if (state == HSS_SEND_DATA_FRAME_HD) {
  110. // HTTP2 DATA
  111. printd("HTTP2 DATA-------------------\n");
  112. void* content = submited->Content();
  113. int content_length = submited->ContentLength();
  114. if (content_length == 0) {
  115. state = HSS_SEND_DONE;
  116. }
  117. else {
  118. state = HSS_SEND_DATA;
  119. *data = (char*)content;
  120. *len = content_length;
  121. }
  122. }
  123. else if (state == HSS_SEND_DATA) {
  124. state = HSS_SEND_DONE;
  125. if (submited->ContentType() == APPLICATION_GRPC) {
  126. if (type == HTTP_SERVER) {
  127. // grpc HEADERS grpc-status
  128. printd("grpc HEADERS grpc-status-----------------\n");
  129. int flags = NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS;
  130. nghttp2_nv nv = make_nv("grpc_status", "0");
  131. nghttp2_submit_headers(session, flags, stream_id, NULL, &nv, 1, NULL);
  132. *len = nghttp2_session_mem_send(session, (const uint8_t**)data);
  133. }
  134. }
  135. }
  136. printd("GetSendData %d\n", *len);
  137. return *len;
  138. }
  139. int Http2Session::FeedRecvData(const char* data, size_t len) {
  140. printd("nghttp2_session_mem_recv %d\n", len);
  141. size_t ret = nghttp2_session_mem_recv(session, (const uint8_t*)data, len);
  142. if (ret != len) {
  143. error = ret;
  144. }
  145. return (int)ret;
  146. }
  147. bool Http2Session::WantRecv() {
  148. return stream_id == -1 || stream_closed == 0;
  149. }
  150. int Http2Session::SubmitRequest(HttpRequest* req) {
  151. submited = req;
  152. std::vector<nghttp2_nv> nvs;
  153. char c_str[256] = {0};
  154. req->ParseUrl();
  155. nvs.push_back(make_nv(":method", http_method_str(req->method)));
  156. nvs.push_back(make_nv(":path", req->path.c_str()));
  157. nvs.push_back(make_nv(":scheme", req->https ? "https" : "http"));
  158. if (req->port == 0 ||
  159. req->port == DEFAULT_HTTP_PORT ||
  160. req->port == DEFAULT_HTTPS_PORT) {
  161. nvs.push_back(make_nv(":authority", req->host.c_str()));
  162. }
  163. else {
  164. snprintf(c_str, sizeof(c_str), "%s:%d", req->host.c_str(), req->port);
  165. nvs.push_back(make_nv(":authority", c_str));
  166. }
  167. req->FillContentType();
  168. req->FillContentLength();
  169. const char* name;
  170. const char* value;
  171. for (auto& header : req->headers) {
  172. name = header.first.c_str();
  173. value = header.second.c_str();
  174. strlower((char*)name);
  175. if (strcmp(name, "connection") == 0) {
  176. // HTTP2 default keep-alive
  177. continue;
  178. }
  179. if (strcmp(name, "content-length") == 0) {
  180. // HTTP2 have frame_hd.length
  181. continue;
  182. }
  183. nvs.push_back(make_nv2(name, value, header.first.size(), header.second.size()));
  184. }
  185. int flags = NGHTTP2_FLAG_END_HEADERS;
  186. // we set EOS on DATA frame
  187. stream_id = nghttp2_submit_headers(session, flags, -1, NULL, &nvs[0], nvs.size(), NULL);
  188. // avoid DATA_SOURCE_COPY, we do not use nghttp2_submit_data
  189. // nghttp2_data_provider data_prd;
  190. // data_prd.read_callback = data_source_read_callback;
  191. //stream_id = nghttp2_submit_request(session, NULL, &nvs[0], nvs.size(), &data_prd, NULL);
  192. stream_closed = 0;
  193. state = HSS_SEND_HEADERS;
  194. return 0;
  195. }
  196. int Http2Session::SubmitResponse(HttpResponse* res) {
  197. submited = res;
  198. std::vector<nghttp2_nv> nvs;
  199. char c_str[256] = {0};
  200. snprintf(c_str, sizeof(c_str), "%d", res->status_code);
  201. nvs.push_back(make_nv(":status", c_str));
  202. res->FillContentType();
  203. res->FillContentLength();
  204. const char* name;
  205. const char* value;
  206. if (parsed && parsed->ContentType() == APPLICATION_GRPC) {
  207. // correct content_type: application/grpc
  208. if (res->ContentType() != APPLICATION_GRPC) {
  209. res->content_type = APPLICATION_GRPC;
  210. res->headers["content-type"] = http_content_type_str(APPLICATION_GRPC);
  211. }
  212. }
  213. for (auto& header : res->headers) {
  214. name = header.first.c_str();
  215. value = header.second.c_str();
  216. strlower((char*)name);
  217. if (strcmp(name, "connection") == 0) {
  218. // HTTP2 default keep-alive
  219. continue;
  220. }
  221. if (strcmp(name, "content-length") == 0) {
  222. // HTTP2 have frame_hd.length
  223. continue;
  224. }
  225. nvs.push_back(make_nv2(name, value, header.first.size(), header.second.size()));
  226. }
  227. int flags = NGHTTP2_FLAG_END_HEADERS;
  228. // we set EOS on DATA frame
  229. if (stream_id == -1) {
  230. // upgrade
  231. nghttp2_session_upgrade(session, NULL, 0, NULL);
  232. stream_id = 1;
  233. }
  234. nghttp2_submit_headers(session, flags, stream_id, NULL, &nvs[0], nvs.size(), NULL);
  235. // avoid DATA_SOURCE_COPY, we do not use nghttp2_submit_data
  236. // data_prd.read_callback = data_source_read_callback;
  237. //stream_id = nghttp2_submit_request(session, NULL, &nvs[0], nvs.size(), &data_prd, NULL);
  238. //nghttp2_submit_response(session, stream_id, &nvs[0], nvs.size(), &data_prd);
  239. stream_closed = 0;
  240. state = HSS_SEND_HEADERS;
  241. return 0;
  242. }
  243. int Http2Session::InitResponse(HttpResponse* res) {
  244. res->Reset();
  245. res->http_major = 2;
  246. res->http_minor = 0;
  247. parsed = res;
  248. return 0;
  249. }
  250. int Http2Session::InitRequest(HttpRequest* req) {
  251. req->Reset();
  252. req->http_major = 2;
  253. req->http_minor = 0;
  254. parsed = req;
  255. return 0;
  256. }
  257. int Http2Session::GetError() {
  258. return error;
  259. }
  260. const char* Http2Session::StrError(int error) {
  261. return nghttp2_http2_strerror(error);
  262. }
  263. nghttp2_session_callbacks* Http2Session::cbs = NULL;
  264. int on_header_callback(nghttp2_session *session,
  265. const nghttp2_frame *frame,
  266. const uint8_t *_name, size_t namelen,
  267. const uint8_t *_value, size_t valuelen,
  268. uint8_t flags, void *userdata) {
  269. printd("on_header_callback\n");
  270. print_frame_hd(&frame->hd);
  271. const char* name = (const char*)_name;
  272. const char* value = (const char*)_value;
  273. printd("%s: %s\n", name, value);
  274. Http2Session* hss = (Http2Session*)userdata;
  275. if (*name == ':') {
  276. if (hss->parsed->type == HTTP_REQUEST) {
  277. // :method :path :scheme :authority
  278. HttpRequest* req = (HttpRequest*)hss->parsed;
  279. if (strcmp(name, ":method") == 0) {
  280. req->method = http_method_enum(value);
  281. }
  282. else if (strcmp(name, ":path") == 0) {
  283. req->url = value;
  284. }
  285. else if (strcmp(name, ":scheme") == 0) {
  286. req->headers["Scheme"] = value;
  287. }
  288. else if (strcmp(name, ":authority") == 0) {
  289. req->headers["Host"] = value;
  290. }
  291. }
  292. else if (hss->parsed->type == HTTP_RESPONSE) {
  293. HttpResponse* res = (HttpResponse*)hss->parsed;
  294. if (strcmp(name, ":status") == 0) {
  295. res->status_code = (http_status)atoi(value);
  296. }
  297. }
  298. }
  299. else {
  300. hss->parsed->headers[name] = value;
  301. if (strcmp(name, "content-type") == 0) {
  302. hss->parsed->content_type = http_content_type_enum(value);
  303. }
  304. }
  305. return 0;
  306. }
  307. int on_data_chunk_recv_callback(nghttp2_session *session,
  308. uint8_t flags, int32_t stream_id, const uint8_t *data,
  309. size_t len, void *userdata) {
  310. printd("on_data_chunk_recv_callback\n");
  311. printd("stream_id=%d length=%d\n", stream_id, (int)len);
  312. //printd("%.*s\n", (int)len, data);
  313. Http2Session* hss = (Http2Session*)userdata;
  314. if (hss->parsed->ContentType() == APPLICATION_GRPC) {
  315. // grpc_message_hd
  316. printd("grpc Length-Prefixed-Message-----------------\n");
  317. if (len >= GRPC_MESSAGE_HDLEN) {
  318. data += GRPC_MESSAGE_HDLEN;
  319. len -= GRPC_MESSAGE_HDLEN;
  320. }
  321. }
  322. hss->parsed->body.insert(hss->parsed->body.size(), (const char*)data, len);
  323. return 0;
  324. }
  325. int on_frame_recv_callback(nghttp2_session *session,
  326. const nghttp2_frame *frame, void *userdata) {
  327. printd("on_frame_recv_callback\n");
  328. print_frame_hd(&frame->hd);
  329. Http2Session* hss = (Http2Session*)userdata;
  330. switch (frame->hd.type) {
  331. case NGHTTP2_DATA:
  332. case NGHTTP2_HEADERS:
  333. hss->stream_id = frame->hd.stream_id;
  334. if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
  335. printd("on_stream_closed stream_id=%d\n", hss->stream_id);
  336. hss->stream_closed = 1;
  337. }
  338. break;
  339. default:
  340. break;
  341. }
  342. return 0;
  343. }
  344. #endif