| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include "private-lib-core.h"
- /*
- * bitmap of control messages that are valid to receive for each http2 state
- */
- static const uint16_t http2_rx_validity[] = {
- /* LWS_H2S_IDLE */
- (1 << LWS_H2_FRAME_TYPE_SETTINGS) |
- (1 << LWS_H2_FRAME_TYPE_PRIORITY) |
- // (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE)| /* ignore */
- (1 << LWS_H2_FRAME_TYPE_HEADERS) |
- (1 << LWS_H2_FRAME_TYPE_CONTINUATION),
- /* LWS_H2S_RESERVED_LOCAL */
- (1 << LWS_H2_FRAME_TYPE_SETTINGS) |
- (1 << LWS_H2_FRAME_TYPE_RST_STREAM) |
- (1 << LWS_H2_FRAME_TYPE_PRIORITY) |
- (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE),
- /* LWS_H2S_RESERVED_REMOTE */
- (1 << LWS_H2_FRAME_TYPE_SETTINGS) |
- (1 << LWS_H2_FRAME_TYPE_HEADERS) |
- (1 << LWS_H2_FRAME_TYPE_CONTINUATION) |
- (1 << LWS_H2_FRAME_TYPE_RST_STREAM) |
- (1 << LWS_H2_FRAME_TYPE_PRIORITY),
- /* LWS_H2S_OPEN */
- (1 << LWS_H2_FRAME_TYPE_DATA) |
- (1 << LWS_H2_FRAME_TYPE_HEADERS) |
- (1 << LWS_H2_FRAME_TYPE_PRIORITY) |
- (1 << LWS_H2_FRAME_TYPE_RST_STREAM) |
- (1 << LWS_H2_FRAME_TYPE_SETTINGS) |
- (1 << LWS_H2_FRAME_TYPE_PUSH_PROMISE) |
- (1 << LWS_H2_FRAME_TYPE_PING) |
- (1 << LWS_H2_FRAME_TYPE_GOAWAY) |
- (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |
- (1 << LWS_H2_FRAME_TYPE_CONTINUATION),
- /* LWS_H2S_HALF_CLOSED_REMOTE */
- (1 << LWS_H2_FRAME_TYPE_SETTINGS) |
- (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |
- (1 << LWS_H2_FRAME_TYPE_PRIORITY) |
- (1 << LWS_H2_FRAME_TYPE_RST_STREAM),
- /* LWS_H2S_HALF_CLOSED_LOCAL */
- (1 << LWS_H2_FRAME_TYPE_DATA) |
- (1 << LWS_H2_FRAME_TYPE_HEADERS) |
- (1 << LWS_H2_FRAME_TYPE_PRIORITY) |
- (1 << LWS_H2_FRAME_TYPE_RST_STREAM) |
- (1 << LWS_H2_FRAME_TYPE_SETTINGS) |
- (1 << LWS_H2_FRAME_TYPE_PUSH_PROMISE) |
- (1 << LWS_H2_FRAME_TYPE_PING) |
- (1 << LWS_H2_FRAME_TYPE_GOAWAY) |
- (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |
- (1 << LWS_H2_FRAME_TYPE_CONTINUATION),
- /* LWS_H2S_CLOSED */
- (1 << LWS_H2_FRAME_TYPE_SETTINGS) |
- (1 << LWS_H2_FRAME_TYPE_PRIORITY) |
- (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |
- (1 << LWS_H2_FRAME_TYPE_RST_STREAM),
- };
- static const char *preface = "PRI * HTTP/2.0\x0d\x0a\x0d\x0aSM\x0d\x0a\x0d\x0a";
- static const char * const h2_state_names[] = {
- "LWS_H2S_IDLE",
- "LWS_H2S_RESERVED_LOCAL",
- "LWS_H2S_RESERVED_REMOTE",
- "LWS_H2S_OPEN",
- "LWS_H2S_HALF_CLOSED_REMOTE",
- "LWS_H2S_HALF_CLOSED_LOCAL",
- "LWS_H2S_CLOSED",
- };
- #if 0
- static const char * const h2_setting_names[] = {
- "",
- "H2SET_HEADER_TABLE_SIZE",
- "H2SET_ENABLE_PUSH",
- "H2SET_MAX_CONCURRENT_STREAMS",
- "H2SET_INITIAL_WINDOW_SIZE",
- "H2SET_MAX_FRAME_SIZE",
- "H2SET_MAX_HEADER_LIST_SIZE",
- "reserved",
- "H2SET_ENABLE_CONNECT_PROTOCOL"
- };
- void
- lws_h2_dump_settings(struct http2_settings *set)
- {
- int n;
- for (n = 1; n < H2SET_COUNT; n++)
- lwsl_notice(" %30s: %10d\n", h2_setting_names[n], set->s[n]);
- }
- #else
- void
- lws_h2_dump_settings(struct http2_settings *set)
- {
- }
- #endif
- struct lws_h2_protocol_send *
- lws_h2_new_pps(enum lws_h2_protocol_send_type type)
- {
- struct lws_h2_protocol_send *pps = lws_malloc(sizeof(*pps), "pps");
- if (pps)
- pps->type = type;
- return pps;
- }
- void lws_h2_init(struct lws *wsi)
- {
- wsi->h2.h2n->our_set = wsi->a.vhost->h2.set;
- wsi->h2.h2n->peer_set = lws_h2_defaults;
- }
- void
- lws_h2_state(struct lws *wsi, enum lws_h2_states s)
- {
- if (!wsi)
- return;
- lwsl_info("%s: wsi %p: state %s -> %s\n", __func__, wsi,
- h2_state_names[wsi->h2.h2_state],
- h2_state_names[s]);
-
- (void)h2_state_names;
- wsi->h2.h2_state = (uint8_t)s;
- }
- int
- lws_h2_update_peer_txcredit(struct lws *wsi, int sid, int bump)
- {
- struct lws *nwsi = lws_get_network_wsi(wsi);
- struct lws_h2_protocol_send *pps;
- assert(wsi);
- if (!bump)
- return 0;
- if (sid == -1)
- sid = wsi->mux.my_sid;
- lwsl_info("%s: sid %d: bump %d -> %d\n", __func__, sid, bump,
- (int)wsi->txc.peer_tx_cr_est + bump);
- pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
- if (!pps)
- return 1;
- pps->u.update_window.sid = sid;
- pps->u.update_window.credit = bump;
- wsi->txc.peer_tx_cr_est += bump;
- lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
- lws_pps_schedule(wsi, pps);
- pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
- if (!pps)
- return 1;
- pps->u.update_window.sid = 0;
- pps->u.update_window.credit = bump;
- nwsi->txc.peer_tx_cr_est += bump;
- lws_wsi_txc_describe(&nwsi->txc, __func__, nwsi->mux.my_sid);
- lws_pps_schedule(nwsi, pps);
- return 0;
- }
- int
- lws_h2_get_peer_txcredit_estimate(struct lws *wsi)
- {
- lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
- return (int)wsi->txc.peer_tx_cr_est;
- }
- static int
- lws_h2_update_peer_txcredit_thresh(struct lws *wsi, int sid, int threshold, int bump)
- {
- if (wsi->txc.peer_tx_cr_est > threshold)
- return 0;
- return lws_h2_update_peer_txcredit(wsi, sid, bump);
- }
- struct lws *
- lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
- unsigned int sid)
- {
- struct lws *wsi;
- struct lws *nwsi = lws_get_network_wsi(parent_wsi);
- struct lws_h2_netconn *h2n = nwsi->h2.h2n;
- /*
- * The identifier of a newly established stream MUST be numerically
- * greater than all streams that the initiating endpoint has opened or
- * reserved. This governs streams that are opened using a HEADERS frame
- * and streams that are reserved using PUSH_PROMISE. An endpoint that
- * receives an unexpected stream identifier MUST respond with a
- * connection error (Section 5.4.1) of type PROTOCOL_ERROR.
- */
- if (sid <= h2n->highest_sid_opened) {
- lwsl_info("%s: tried to open lower sid %d (%d)\n", __func__,
- sid, (int)h2n->highest_sid_opened);
- lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, "Bad sid");
- return NULL;
- }
- /* no more children allowed by parent */
- if (parent_wsi->mux.child_count + 1 >
- parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
- lwsl_notice("reached concurrent stream limit\n");
- return NULL;
- }
- wsi = lws_create_new_server_wsi(vh, parent_wsi->tsi);
- if (!wsi) {
- lwsl_notice("new server wsi failed (vh %p)\n", vh);
- return NULL;
- }
- h2n->highest_sid_opened = sid;
- lws_wsi_mux_insert(wsi, parent_wsi, sid);
- if (sid >= h2n->highest_sid)
- h2n->highest_sid = sid + 2;
- wsi->mux_substream = 1;
- wsi->seen_nonpseudoheader = 0;
- wsi->txc.tx_cr = nwsi->h2.h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
- wsi->txc.peer_tx_cr_est =
- nwsi->h2.h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
- lwsi_set_state(wsi, LRS_ESTABLISHED);
- lwsi_set_role(wsi, lwsi_role(parent_wsi));
- wsi->a.protocol = &vh->protocols[0];
- if (lws_ensure_user_space(wsi))
- goto bail1;
- #if defined(LWS_WITH_SERVER_STATUS)
- wsi->a.vhost->conn_stats.h2_subs++;
- #endif
- #if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
- if (lws_adopt_ss_server_accept(wsi))
- goto bail1;
- #endif
- /* get the ball rolling */
- lws_validity_confirmed(wsi);
- lwsl_info("%s: %p new ch %p, sid %d, usersp=%p\n", __func__,
- parent_wsi, wsi, sid, wsi->user_space);
- lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
- lws_wsi_txc_describe(&nwsi->txc, __func__, 0);
- return wsi;
- bail1:
- /* undo the insert */
- parent_wsi->mux.child_list = wsi->mux.sibling_list;
- parent_wsi->mux.child_count--;
- vh->context->count_wsi_allocated--;
- if (wsi->user_space)
- lws_free_set_NULL(wsi->user_space);
- vh->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
- lws_vhost_unbind_wsi(wsi);
- lws_free(wsi);
- return NULL;
- }
- struct lws *
- lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi)
- {
- struct lws *nwsi = lws_get_network_wsi(parent_wsi);
- /* no more children allowed by parent */
- if (parent_wsi->mux.child_count + 1 >
- parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
- lwsl_notice("reached concurrent stream limit\n");
- return NULL;
- }
- /* sid is set just before issuing the headers, ensuring monoticity */
- wsi->seen_nonpseudoheader = 0;
- #if defined(LWS_WITH_CLIENT)
- wsi->client_mux_substream = 1;
- #endif
- wsi->h2.initialized = 1;
- #if 0
- /* only assign sid at header send time when we know it */
- if (!wsi->mux.my_sid) {
- wsi->mux.my_sid = nwsi->h2.h2n->highest_sid;
- nwsi->h2.h2n->highest_sid += 2;
- }
- #endif
- lwsl_info("%s: binding wsi %p to sid %d (next %d)\n", __func__,
- wsi, (int)wsi->mux.my_sid, (int)nwsi->h2.h2n->highest_sid);
- lws_wsi_mux_insert(wsi, parent_wsi, wsi->mux.my_sid);
- wsi->txc.tx_cr = nwsi->h2.h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
- wsi->txc.peer_tx_cr_est =
- nwsi->h2.h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
- lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
- if (lws_ensure_user_space(wsi))
- goto bail1;
- lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS,
- &role_ops_h2);
- lws_callback_on_writable(wsi);
- #if defined(LWS_WITH_SERVER_STATUS)
- wsi->a.vhost->conn_stats.h2_subs++;
- #endif
- return wsi;
- bail1:
- /* undo the insert */
- parent_wsi->mux.child_list = wsi->mux.sibling_list;
- parent_wsi->mux.child_count--;
- if (wsi->user_space)
- lws_free_set_NULL(wsi->user_space);
- wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
- lws_free(wsi);
- return NULL;
- }
- int lws_h2_issue_preface(struct lws *wsi)
- {
- struct lws_h2_netconn *h2n = wsi->h2.h2n;
- struct lws_h2_protocol_send *pps;
- if (lws_issue_raw(wsi, (uint8_t *)preface, strlen(preface)) !=
- (int)strlen(preface))
- return 1;
- lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS,
- &role_ops_h2);
- h2n->count = 0;
- wsi->txc.tx_cr = 65535;
- /*
- * we must send a settings frame
- */
- pps = lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS);
- if (!pps)
- return 1;
- lws_pps_schedule(wsi, pps);
- lwsl_info("%s: h2 client sending settings\n", __func__);
- return 0;
- }
- void
- lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps)
- {
- struct lws *nwsi = lws_get_network_wsi(wsi);
- struct lws_h2_netconn *h2n = nwsi->h2.h2n;
- pps->next = h2n->pps;
- h2n->pps = pps;
- lws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_DISABLE |
- LWS_RXFLOW_REASON_H2_PPS_PENDING);
- lws_callback_on_writable(wsi);
- }
- int
- lws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason)
- {
- struct lws_h2_netconn *h2n = wsi->h2.h2n;
- struct lws_h2_protocol_send *pps;
- if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
- return 0;
- pps = lws_h2_new_pps(LWS_H2_PPS_GOAWAY);
- if (!pps)
- return 1;
- lwsl_info("%s: %p: ERR 0x%x, '%s'\n", __func__, wsi, (int)err, reason);
- pps->u.ga.err = err;
- pps->u.ga.highest_sid = h2n->highest_sid;
- lws_strncpy(pps->u.ga.str, reason, sizeof(pps->u.ga.str));
- lws_pps_schedule(wsi, pps);
- h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
- return 0;
- }
- int
- lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason)
- {
- struct lws *nwsi = lws_get_network_wsi(wsi);
- struct lws_h2_netconn *h2n = nwsi->h2.h2n;
- struct lws_h2_protocol_send *pps;
- if (!h2n)
- return 0;
- if (!wsi->h2_stream_carries_ws && h2n->type == LWS_H2_FRAME_TYPE_COUNT)
- return 0;
- pps = lws_h2_new_pps(LWS_H2_PPS_RST_STREAM);
- if (!pps)
- return 1;
- lwsl_info("%s: RST_STREAM 0x%x, sid %d, REASON '%s'\n", __func__,
- (int)err, wsi->mux.my_sid, reason);
- pps->u.rs.sid = wsi->mux.my_sid;
- pps->u.rs.err = err;
- lws_pps_schedule(wsi, pps);
- h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
- lws_h2_state(wsi, LWS_H2_STATE_CLOSED);
- return 0;
- }
- int
- lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
- unsigned char *buf, int len)
- {
- struct lws *nwsi = lws_get_network_wsi(wsi);
- unsigned int a, b;
- if (!len)
- return 0;
- if (len < LWS_H2_SETTINGS_LEN)
- return 1;
- while (len >= LWS_H2_SETTINGS_LEN) {
- a = (buf[0] << 8) | buf[1];
- if (!a || a >= H2SET_COUNT)
- goto skip;
- b = buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5];
- switch (a) {
- case H2SET_HEADER_TABLE_SIZE:
- break;
- case H2SET_ENABLE_PUSH:
- if (b > 1) {
- lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
- "ENABLE_PUSH invalid arg");
- return 1;
- }
- break;
- case H2SET_MAX_CONCURRENT_STREAMS:
- break;
- case H2SET_INITIAL_WINDOW_SIZE:
- if (b > 0x7fffffff) {
- lws_h2_goaway(nwsi, H2_ERR_FLOW_CONTROL_ERROR,
- "Inital Window beyond max");
- return 1;
- }
- #if defined(LWS_WITH_CLIENT)
- #if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
- if (
- #else
- if (wsi->flags & LCCSCF_H2_QUIRK_OVERFLOWS_TXCR &&
- #endif
- b == 0x7fffffff) {
- b >>= 4;
- break;
- }
- #endif
- /*
- * In addition to changing the flow-control window for
- * streams that are not yet active, a SETTINGS frame
- * can alter the initial flow-control window size for
- * streams with active flow-control windows (that is,
- * streams in the "open" or "half-closed (remote)"
- * state). When the value of
- * SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver
- * MUST adjust the size of all stream flow-control
- * windows that it maintains by the difference between
- * the new value and the old value.
- */
- lws_start_foreach_ll(struct lws *, w,
- nwsi->mux.child_list) {
- lwsl_info("%s: adi child tc cr %d +%d -> %d",
- __func__, (int)w->txc.tx_cr,
- b - (unsigned int)settings->s[a],
- (int)w->txc.tx_cr + b -
- (unsigned int)settings->s[a]);
- w->txc.tx_cr += b - settings->s[a];
- if (w->txc.tx_cr > 0 &&
- w->txc.tx_cr <=
- (int32_t)(b - settings->s[a]))
- lws_callback_on_writable(w);
- } lws_end_foreach_ll(w, mux.sibling_list);
- break;
- case H2SET_MAX_FRAME_SIZE:
- if (b < wsi->a.vhost->h2.set.s[H2SET_MAX_FRAME_SIZE]) {
- lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
- "Frame size < initial");
- return 1;
- }
- if (b > 0x00ffffff) {
- lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
- "Settings Frame size above max");
- return 1;
- }
- break;
- case H2SET_MAX_HEADER_LIST_SIZE:
- break;
- }
- settings->s[a] = b;
- lwsl_info("http2 settings %d <- 0x%x\n", a, b);
- skip:
- len -= LWS_H2_SETTINGS_LEN;
- buf += LWS_H2_SETTINGS_LEN;
- }
- if (len)
- return 1;
- lws_h2_dump_settings(settings);
- return 0;
- }
- /* RFC7640 Sect 6.9
- *
- * The WINDOW_UPDATE frame can be specific to a stream or to the entire
- * connection. In the former case, the frame's stream identifier
- * indicates the affected stream; in the latter, the value "0" indicates
- * that the entire connection is the subject of the frame.
- *
- * ...
- *
- * Two flow-control windows are applicable: the stream flow-control
- * window and the connection flow-control window. The sender MUST NOT
- * send a flow-controlled frame with a length that exceeds the space
- * available in either of the flow-control windows advertised by the
- * receiver. Frames with zero length with the END_STREAM flag set (that
- * is, an empty DATA frame) MAY be sent if there is no available space
- * in either flow-control window.
- */
- int
- lws_h2_tx_cr_get(struct lws *wsi)
- {
- int c = wsi->txc.tx_cr;
- struct lws *nwsi = lws_get_network_wsi(wsi);
- if (!wsi->mux_substream && !nwsi->upgraded_to_http2)
- return ~0x80000000;
- lwsl_info ("%s: %p: own tx credit %d: nwsi credit %d\n",
- __func__, wsi, c, (int)nwsi->txc.tx_cr);
- if (nwsi->txc.tx_cr < c)
- c = nwsi->txc.tx_cr;
- if (c < 0)
- return 0;
- return c;
- }
- void
- lws_h2_tx_cr_consume(struct lws *wsi, int consumed)
- {
- struct lws *nwsi = lws_get_network_wsi(wsi);
- wsi->txc.tx_cr -= consumed;
- if (nwsi != wsi)
- nwsi->txc.tx_cr -= consumed;
- }
- int lws_h2_frame_write(struct lws *wsi, int type, int flags,
- unsigned int sid, unsigned int len, unsigned char *buf)
- {
- struct lws *nwsi = lws_get_network_wsi(wsi);
- unsigned char *p = &buf[-LWS_H2_FRAME_HEADER_LENGTH];
- int n;
- //if (wsi->h2_stream_carries_ws)
- // lwsl_hexdump_level(LLL_NOTICE, buf, len);
- *p++ = len >> 16;
- *p++ = len >> 8;
- *p++ = len;
- *p++ = type;
- *p++ = flags;
- *p++ = sid >> 24;
- *p++ = sid >> 16;
- *p++ = sid >> 8;
- *p++ = sid;
- lwsl_debug("%s: %p (eff %p). typ %d, fl 0x%x, sid=%d, len=%d, "
- "txcr=%d, nwsi->txcr=%d\n", __func__, wsi, nwsi, type, flags,
- sid, len, (int)wsi->txc.tx_cr, (int)nwsi->txc.tx_cr);
- if (type == LWS_H2_FRAME_TYPE_DATA) {
- if (wsi->txc.tx_cr < (int)len)
- lwsl_info("%s: %p: sending payload len %d"
- " but tx_cr only %d!\n", __func__, wsi,
- len, (int)wsi->txc.tx_cr);
- lws_h2_tx_cr_consume(wsi, len);
- }
- n = lws_issue_raw(nwsi, &buf[-LWS_H2_FRAME_HEADER_LENGTH],
- len + LWS_H2_FRAME_HEADER_LENGTH);
- if (n < 0)
- return n;
- if (n >= LWS_H2_FRAME_HEADER_LENGTH)
- return n - LWS_H2_FRAME_HEADER_LENGTH;
- return n;
- }
- static void lws_h2_set_bin(struct lws *wsi, int n, unsigned char *buf)
- {
- *buf++ = n >> 8;
- *buf++ = n;
- *buf++ = wsi->h2.h2n->our_set.s[n] >> 24;
- *buf++ = wsi->h2.h2n->our_set.s[n] >> 16;
- *buf++ = wsi->h2.h2n->our_set.s[n] >> 8;
- *buf = wsi->h2.h2n->our_set.s[n];
- }
- /* we get called on the network connection */
- int lws_h2_do_pps_send(struct lws *wsi)
- {
- struct lws_h2_netconn *h2n = wsi->h2.h2n;
- struct lws_h2_protocol_send *pps = NULL;
- struct lws *cwsi;
- uint8_t set[LWS_PRE + 64], *p = &set[LWS_PRE], *q;
- int n, m = 0, flags = 0;
- if (!h2n)
- return 1;
- /* get the oldest pps */
- lws_start_foreach_llp(struct lws_h2_protocol_send **, pps1, h2n->pps) {
- if ((*pps1)->next == NULL) { /* we are the oldest in the list */
- pps = *pps1; /* remove us from the list */
- *pps1 = NULL;
- continue;
- }
- } lws_end_foreach_llp(pps1, next);
- if (!pps)
- return 1;
- lwsl_info("%s: %p: %d\n", __func__, wsi, pps->type);
- switch (pps->type) {
- case LWS_H2_PPS_MY_SETTINGS:
- /*
- * if any of our settings varies from h2 "default defaults"
- * then we must inform the peer
- */
- for (n = 1; n < H2SET_COUNT; n++)
- if (h2n->our_set.s[n] != lws_h2_defaults.s[n]) {
- lwsl_debug("sending SETTING %d 0x%x\n", n,
- (unsigned int)
- wsi->h2.h2n->our_set.s[n]);
- lws_h2_set_bin(wsi, n, &set[LWS_PRE + m]);
- m += sizeof(h2n->one_setting);
- }
- n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,
- flags, LWS_H2_STREAM_ID_MASTER, m,
- &set[LWS_PRE]);
- if (n != m) {
- lwsl_info("send %d %d\n", n, m);
- goto bail;
- }
- break;
- case LWS_H2_PPS_SETTINGS_INITIAL_UPDATE_WINDOW:
- q = &set[LWS_PRE];
- *q++ = H2SET_INITIAL_WINDOW_SIZE >> 8;
- *q++ = H2SET_INITIAL_WINDOW_SIZE;
- *q++ = pps->u.update_window.credit >> 24;
- *q++ = pps->u.update_window.credit >> 16;
- *q++ = pps->u.update_window.credit >> 8;
- *q = pps->u.update_window.credit;
- lwsl_debug("%s: resetting initial window to %d\n", __func__,
- (int)pps->u.update_window.credit);
- n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,
- flags, LWS_H2_STREAM_ID_MASTER, 6,
- &set[LWS_PRE]);
- if (n != 6) {
- lwsl_info("send %d %d\n", n, m);
- goto bail;
- }
- break;
- case LWS_H2_PPS_ACK_SETTINGS:
- /* send ack ... always empty */
- n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, 1,
- LWS_H2_STREAM_ID_MASTER, 0,
- &set[LWS_PRE]);
- if (n) {
- lwsl_err("ack tells %d\n", n);
- goto bail;
- }
- wsi->h2_acked_settings = 0;
- /* this is the end of the preface dance then? */
- if (lwsi_state(wsi) == LRS_H2_AWAIT_SETTINGS) {
- lwsi_set_state(wsi, LRS_ESTABLISHED);
- #if defined(LWS_WITH_FILE_OPS)
- wsi->http.fop_fd = NULL;
- #endif
- if (lws_is_ssl(lws_get_network_wsi(wsi)))
- break;
- if (wsi->a.vhost->options &
- LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)
- break;
- /*
- * we need to treat the headers from the upgrade as the
- * first job. So these need to get shifted to sid 1.
- */
- h2n->swsi = lws_wsi_server_new(wsi->a.vhost, wsi, 1);
- if (!h2n->swsi)
- goto bail;
- /* pass on the initial headers to SID 1 */
- h2n->swsi->http.ah = wsi->http.ah;
- wsi->http.ah = NULL;
- lwsl_info("%s: inherited headers %p\n", __func__,
- h2n->swsi->http.ah);
- h2n->swsi->txc.tx_cr =
- h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
- lwsl_info("initial tx credit on conn %p: %d\n",
- h2n->swsi, (int)h2n->swsi->txc.tx_cr);
- h2n->swsi->h2.initialized = 1;
- /* demanded by HTTP2 */
- h2n->swsi->h2.END_STREAM = 1;
- lwsl_info("servicing initial http request\n");
- #if defined(LWS_WITH_SERVER_STATUS)
- wsi->a.vhost->conn_stats.h2_trans++;
- #endif
- #if defined(LWS_WITH_SERVER)
- if (lws_http_action(h2n->swsi))
- goto bail;
- #endif
- break;
- }
- break;
- /*
- * h2 only has PING... ACK = 0 = ping, ACK = 1 = pong
- */
- case LWS_H2_PPS_PING:
- case LWS_H2_PPS_PONG:
- if (pps->type == LWS_H2_PPS_PING)
- lwsl_info("sending PING\n");
- else {
- lwsl_info("sending PONG\n");
- flags = LWS_H2_FLAG_SETTINGS_ACK;
- }
- memcpy(&set[LWS_PRE], pps->u.ping.ping_payload, 8);
- n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING, flags,
- LWS_H2_STREAM_ID_MASTER, 8,
- &set[LWS_PRE]);
- if (n != 8)
- goto bail;
- break;
- case LWS_H2_PPS_GOAWAY:
- lwsl_info("LWS_H2_PPS_GOAWAY\n");
- *p++ = pps->u.ga.highest_sid >> 24;
- *p++ = pps->u.ga.highest_sid >> 16;
- *p++ = pps->u.ga.highest_sid >> 8;
- *p++ = pps->u.ga.highest_sid;
- *p++ = pps->u.ga.err >> 24;
- *p++ = pps->u.ga.err >> 16;
- *p++ = pps->u.ga.err >> 8;
- *p++ = pps->u.ga.err;
- q = (unsigned char *)pps->u.ga.str;
- n = 0;
- while (*q && n++ < (int)sizeof(pps->u.ga.str))
- *p++ = *q++;
- h2n->we_told_goaway = 1;
- n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_GOAWAY, 0,
- LWS_H2_STREAM_ID_MASTER,
- lws_ptr_diff(p, &set[LWS_PRE]),
- &set[LWS_PRE]);
- if (n != 4) {
- lwsl_info("send %d %d\n", n, m);
- goto bail;
- }
- goto bail;
- case LWS_H2_PPS_RST_STREAM:
- lwsl_info("LWS_H2_PPS_RST_STREAM\n");
- *p++ = pps->u.rs.err >> 24;
- *p++ = pps->u.rs.err >> 16;
- *p++ = pps->u.rs.err >> 8;
- *p++ = pps->u.rs.err;
- n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_RST_STREAM,
- 0, pps->u.rs.sid, 4, &set[LWS_PRE]);
- if (n != 4) {
- lwsl_info("send %d %d\n", n, m);
- goto bail;
- }
- cwsi = lws_wsi_mux_from_id(wsi, pps->u.rs.sid);
- if (cwsi) {
- lwsl_debug("%s: closing cwsi %p %s %s (wsi %p)\n",
- __func__, cwsi, cwsi->role_ops->name,
- cwsi->a.protocol->name, wsi);
- lws_close_free_wsi(cwsi, 0, "reset stream");
- }
- break;
- case LWS_H2_PPS_UPDATE_WINDOW:
- lwsl_info("Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n",
- (int)pps->u.update_window.sid,
- (int)pps->u.update_window.credit);
- *p++ = (pps->u.update_window.credit >> 24) & 0x7f; /* 31b */
- *p++ = pps->u.update_window.credit >> 16;
- *p++ = pps->u.update_window.credit >> 8;
- *p++ = pps->u.update_window.credit;
- n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_WINDOW_UPDATE,
- 0, pps->u.update_window.sid, 4,
- &set[LWS_PRE]);
- if (n != 4) {
- lwsl_info("send %d %d\n", n, m);
- goto bail;
- }
- break;
- default:
- break;
- }
- lws_free(pps);
- return 0;
- bail:
- lws_free(pps);
- return 1;
- }
- static int
- lws_h2_parse_end_of_frame(struct lws *wsi);
- /*
- * The frame header part has just completely arrived.
- * Perform actions for header completion.
- */
- static int
- lws_h2_parse_frame_header(struct lws *wsi)
- {
- struct lws_h2_netconn *h2n = wsi->h2.h2n;
- struct lws_h2_protocol_send *pps;
- int n;
- /*
- * We just got the frame header
- */
- h2n->count = 0;
- h2n->swsi = wsi;
- /* b31 is a reserved bit */
- h2n->sid = h2n->sid & 0x7fffffff;
- if (h2n->sid && !(h2n->sid & 1)) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "Even Stream ID");
- return 0;
- }
- /* let the network wsi live a bit longer if subs are active */
- if (!wsi->immortal_substream_count)
- lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
- wsi->a.vhost->keepalive_timeout ?
- wsi->a.vhost->keepalive_timeout : 31);
- if (h2n->sid)
- h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
- lwsl_debug("%p (%p): fr hdr: typ 0x%x, fla 0x%x, sid 0x%x, len 0x%x\n",
- wsi, h2n->swsi, h2n->type, h2n->flags, (unsigned int)h2n->sid,
- (unsigned int)h2n->length);
- if (h2n->we_told_goaway && h2n->sid > h2n->highest_sid)
- h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
- if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
- return 0;
- if (h2n->length > h2n->our_set.s[H2SET_MAX_FRAME_SIZE]) {
- /*
- * peer sent us something bigger than we told
- * it we would allow
- */
- lwsl_info("%s: received oversize frame %d\n", __func__,
- (unsigned int)h2n->length);
- lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
- "Peer ignored our frame size setting");
- return 1;
- }
- if (h2n->swsi)
- lwsl_info("%s: wsi %p, State: %s, received cmd %d\n",
- __func__, h2n->swsi,
- h2_state_names[h2n->swsi->h2.h2_state], h2n->type);
- else {
- /* if it's data, either way no swsi means CLOSED state */
- if (h2n->type == LWS_H2_FRAME_TYPE_DATA) {
- if (h2n->sid <= h2n->highest_sid_opened
- #if defined(LWS_WITH_CLIENT)
- && wsi->client_h2_alpn
- #endif
- ) {
- lwsl_notice("ignoring straggling data fl 0x%x\n",
- h2n->flags);
- /* ie, IGNORE */
- h2n->type = LWS_H2_FRAME_TYPE_COUNT;
- } else {
- lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
- "Data for nonexistent sid");
- return 0;
- }
- }
- /* if the sid is credible, treat as wsi for it closed */
- if (h2n->sid > h2n->highest_sid_opened &&
- h2n->type != LWS_H2_FRAME_TYPE_HEADERS &&
- h2n->type != LWS_H2_FRAME_TYPE_PRIORITY) {
- /* if not credible, reject it */
- lwsl_info("%s: wsi %p, No child for sid %d, rxcmd %d\n",
- __func__, h2n->swsi, (unsigned int)h2n->sid, h2n->type);
- lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
- "Data for nonexistent sid");
- return 0;
- }
- }
- if (h2n->swsi && h2n->sid &&
- !(http2_rx_validity[h2n->swsi->h2.h2_state] & (1 << h2n->type))) {
- lwsl_info("%s: wsi %p, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\n",
- __func__, h2n->swsi,
- h2_state_names[h2n->swsi->h2.h2_state], h2n->type,
- http2_rx_validity[h2n->swsi->h2.h2_state]);
- if (h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED ||
- h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE)
- n = H2_ERR_STREAM_CLOSED;
- else
- n = H2_ERR_PROTOCOL_ERROR;
- lws_h2_goaway(wsi, n, "invalid rx for state");
- return 0;
- }
- if (h2n->cont_exp && (h2n->cont_exp_sid != h2n->sid ||
- h2n->type != LWS_H2_FRAME_TYPE_CONTINUATION)) {
- lwsl_info("%s: expected cont on sid %u (got %d on sid %u)\n",
- __func__, (unsigned int)h2n->cont_exp_sid, h2n->type,
- (unsigned int)h2n->sid);
- h2n->cont_exp = 0;
- if (h2n->cont_exp_headers)
- n = H2_ERR_COMPRESSION_ERROR;
- else
- n = H2_ERR_PROTOCOL_ERROR;
- lws_h2_goaway(wsi, n, "Continuation hdrs State");
- return 0;
- }
- switch (h2n->type) {
- case LWS_H2_FRAME_TYPE_DATA:
- lwsl_info("seen incoming LWS_H2_FRAME_TYPE_DATA start\n");
- if (!h2n->sid) {
- lwsl_info("DATA: 0 sid\n");
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "DATA 0 sid");
- break;
- }
- lwsl_info("Frame header DATA: sid %u, flags 0x%x, len %u\n",
- (unsigned int)h2n->sid, h2n->flags,
- (unsigned int)h2n->length);
- if (!h2n->swsi) {
- lwsl_notice("DATA: NULL swsi\n");
- break;
- }
- lwsl_info("DATA rx on state %d\n", h2n->swsi->h2.h2_state);
- if (
- h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE ||
- h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED) {
- lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, "conn closed");
- break;
- }
- if (h2n->length == 0)
- lws_h2_parse_end_of_frame(wsi);
- break;
- case LWS_H2_FRAME_TYPE_PRIORITY:
- lwsl_info("LWS_H2_FRAME_TYPE_PRIORITY complete frame\n");
- if (!h2n->sid) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "Priority has 0 sid");
- break;
- }
- if (h2n->length != 5) {
- lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
- "Priority has length other than 5");
- break;
- }
- break;
- case LWS_H2_FRAME_TYPE_PUSH_PROMISE:
- lwsl_info("LWS_H2_FRAME_TYPE_PUSH_PROMISE complete frame\n");
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "Server only");
- break;
- case LWS_H2_FRAME_TYPE_GOAWAY:
- lwsl_debug("LWS_H2_FRAME_TYPE_GOAWAY received\n");
- break;
- case LWS_H2_FRAME_TYPE_RST_STREAM:
- if (!h2n->sid)
- return 1;
- if (!h2n->swsi) {
- if (h2n->sid <= h2n->highest_sid_opened)
- break;
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "crazy sid on RST_STREAM");
- return 1;
- }
- if (h2n->length != 4) {
- lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
- "RST_STREAM can only be length 4");
- break;
- }
- lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
- break;
- case LWS_H2_FRAME_TYPE_SETTINGS:
- lwsl_info("LWS_H2_FRAME_TYPE_SETTINGS complete frame\n");
- /* nonzero sid on settings is illegal */
- if (h2n->sid) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "Settings has nonzero sid");
- break;
- }
- if (!(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) {
- if (h2n->length % 6) {
- lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
- "Settings length error");
- break;
- }
- if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
- return 0;
- if (wsi->upgraded_to_http2 &&
- #if defined(LWS_WITH_CLIENT)
- (!(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) ||
- #else
- (
- #endif
- !wsi->h2_acked_settings)) {
- pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
- if (!pps)
- return 1;
- lws_pps_schedule(wsi, pps);
- wsi->h2_acked_settings = 1;
- }
- break;
- }
- /* came to us with ACK set... not allowed to have payload */
- if (h2n->length) {
- lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
- "Settings with ACK not allowed payload");
- break;
- }
- break;
- case LWS_H2_FRAME_TYPE_PING:
- if (h2n->sid) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "Ping has nonzero sid");
- break;
- }
- if (h2n->length != 8) {
- lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
- "Ping payload can only be 8");
- break;
- }
- break;
- case LWS_H2_FRAME_TYPE_CONTINUATION:
- lwsl_info("LWS_H2_FRAME_TYPE_CONTINUATION: sid = %u %d %d\n",
- (unsigned int)h2n->sid, (int)h2n->cont_exp,
- (int)h2n->cont_exp_sid);
- if (!h2n->cont_exp ||
- h2n->cont_exp_sid != h2n->sid ||
- !h2n->sid ||
- !h2n->swsi) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "unexpected CONTINUATION");
- break;
- }
- if (h2n->swsi->h2.END_HEADERS) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "END_HEADERS already seen");
- break;
- }
- /* END_STREAM is in HEADERS, skip resetting it */
- goto update_end_headers;
- case LWS_H2_FRAME_TYPE_HEADERS:
- lwsl_info("HEADERS: frame header: sid = %u\n",
- (unsigned int)h2n->sid);
- if (!h2n->sid) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "sid 0");
- return 1;
- }
- if (h2n->swsi && !h2n->swsi->h2.END_STREAM &&
- h2n->swsi->h2.END_HEADERS &&
- !(h2n->flags & LWS_H2_FLAG_END_STREAM)) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "extra HEADERS together");
- return 1;
- }
- #if defined(LWS_WITH_CLIENT)
- if (wsi->client_h2_alpn) {
- if (h2n->sid) {
- h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
- lwsl_info("HEADERS: nwsi %p: sid %u mapped "
- "to wsi %p\n", wsi,
- (unsigned int)h2n->sid, h2n->swsi);
- if (!h2n->swsi)
- break;
- }
- goto update_end_headers;
- }
- #endif
- if (!h2n->swsi) {
- /* no more children allowed by parent */
- if (wsi->mux.child_count + 1 >
- wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "Another stream not allowed");
- return 1;
- }
- /*
- * The peer has sent us a HEADERS implying the creation
- * of a new stream
- */
- h2n->swsi = lws_wsi_server_new(wsi->a.vhost, wsi,
- h2n->sid);
- if (!h2n->swsi) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "OOM");
- return 1;
- }
- if (h2n->sid >= h2n->highest_sid)
- h2n->highest_sid = h2n->sid + 2;
- h2n->swsi->h2.initialized = 1;
- if (lws_h2_update_peer_txcredit(h2n->swsi,
- h2n->swsi->mux.my_sid, 4 * 65536))
- goto cleanup_wsi;
- }
- /*
- * ah needs attaching to child wsi, even though
- * we only fill it from network wsi
- */
- if (!h2n->swsi->http.ah)
- if (lws_header_table_attach(h2n->swsi, 0)) {
- lwsl_err("%s: Failed to get ah\n", __func__);
- return 1;
- }
- /*
- * The first use of a new stream identifier implicitly closes
- * all streams in the "idle" state that might have been
- * initiated by that peer with a lower-valued stream identifier.
- *
- * For example, if a client sends a HEADERS frame on stream 7
- * without ever sending a frame on stream 5, then stream 5
- * transitions to the "closed" state when the first frame for
- * stream 7 is sent or received.
- */
- lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) {
- if (w->mux.my_sid < h2n->sid &&
- w->h2.h2_state == LWS_H2_STATE_IDLE)
- lws_close_free_wsi(w, 0, "h2 sid close");
- assert(w->mux.sibling_list != w);
- } lws_end_foreach_ll(w, mux.sibling_list);
- if (lws_check_opt(h2n->swsi->a.vhost->options,
- LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL)) {
- /*
- * We don't directly timeout streams that enter the
- * half-closed remote state, allowing immortal long
- * poll
- */
- lws_mux_mark_immortal(h2n->swsi);
- lwsl_info("%s: %p: h2 stream entering long poll\n",
- __func__, h2n->swsi);
- } else {
- h2n->swsi->h2.END_STREAM =
- !!(h2n->flags & LWS_H2_FLAG_END_STREAM);
- lwsl_debug("%s: hdr END_STREAM = %d\n",__func__,
- h2n->swsi->h2.END_STREAM);
- }
- h2n->cont_exp = !(h2n->flags & LWS_H2_FLAG_END_HEADERS);
- h2n->cont_exp_sid = h2n->sid;
- h2n->cont_exp_headers = 1;
- // lws_header_table_reset(h2n->swsi, 0);
- update_end_headers:
- /* no END_HEADERS means CONTINUATION must come */
- h2n->swsi->h2.END_HEADERS =
- !!(h2n->flags & LWS_H2_FLAG_END_HEADERS);
- lwsl_info("%p: END_HEADERS %d\n", h2n->swsi,
- h2n->swsi->h2.END_HEADERS);
- if (h2n->swsi->h2.END_HEADERS)
- h2n->cont_exp = 0;
- lwsl_debug("END_HEADERS %d\n", h2n->swsi->h2.END_HEADERS);
- break;
- cleanup_wsi:
- return 1;
- case LWS_H2_FRAME_TYPE_WINDOW_UPDATE:
- if (h2n->length != 4) {
- lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
- "window update frame not 4");
- break;
- }
- lwsl_info("LWS_H2_FRAME_TYPE_WINDOW_UPDATE\n");
- break;
- case LWS_H2_FRAME_TYPE_COUNT:
- break;
- default:
- lwsl_info("%s: ILLEGAL FRAME TYPE %d\n", __func__, h2n->type);
- h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
- break;
- }
- if (h2n->length == 0)
- h2n->frame_state = 0;
- return 0;
- }
- static const char * const method_names[] = {
- "GET", "POST",
- #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
- "OPTIONS", "PUT", "PATCH", "DELETE",
- #endif
- "CONNECT", "HEAD"
- };
- static unsigned char method_index[] = {
- WSI_TOKEN_GET_URI,
- WSI_TOKEN_POST_URI,
- #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
- WSI_TOKEN_OPTIONS_URI,
- WSI_TOKEN_PUT_URI,
- WSI_TOKEN_PATCH_URI,
- WSI_TOKEN_DELETE_URI,
- #endif
- WSI_TOKEN_CONNECT,
- WSI_TOKEN_HEAD_URI,
- };
- /*
- * The last byte of the whole frame has been handled.
- * Perform actions for frame completion.
- *
- * This is the crunch time for parsing that may have occured on a network
- * wsi with a pending partial send... we may call lws_http_action() to send
- * a response, conflicting with the partial.
- *
- * So in that case we change the wsi state and do the lws_http_action() in the
- * WRITABLE handler as a priority.
- */
- static int
- lws_h2_parse_end_of_frame(struct lws *wsi)
- {
- struct lws_h2_netconn *h2n = wsi->h2.h2n;
- struct lws *eff_wsi = wsi;
- const char *p;
- int n;
- h2n->frame_state = 0;
- h2n->count = 0;
- if (h2n->sid)
- h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
- if (h2n->sid > h2n->highest_sid)
- h2n->highest_sid = h2n->sid;
- if (h2n->collected_priority && (h2n->dep & ~(1u << 31)) == h2n->sid) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "depends on own sid");
- return 0;
- }
- switch (h2n->type) {
- case LWS_H2_FRAME_TYPE_SETTINGS:
- #if defined(LWS_WITH_CLIENT)
- if (wsi->client_h2_alpn && !wsi->client_mux_migrated &&
- !(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) {
- struct lws_h2_protocol_send *pps;
- /* migrate original client ask on to substream 1 */
- #if defined(LWS_WITH_FILE_OPS)
- wsi->http.fop_fd = NULL;
- #endif
- lwsl_info("%s: migrating\n", __func__);
- wsi->client_mux_migrated = 1;
- /*
- * we need to treat the headers from the upgrade as the
- * first job. So these need to get shifted to sid 1.
- */
- h2n->swsi = lws_wsi_server_new(wsi->a.vhost, wsi, 1);
- if (!h2n->swsi)
- return 1;
- h2n->sid = 1;
- assert(lws_wsi_mux_from_id(wsi, 1) == h2n->swsi);
- lws_role_transition(wsi, LWSIFR_CLIENT,
- LRS_H2_WAITING_TO_SEND_HEADERS,
- &role_ops_h2);
- lws_role_transition(h2n->swsi, LWSIFR_CLIENT,
- LRS_H2_WAITING_TO_SEND_HEADERS,
- &role_ops_h2);
- /* pass on the initial headers to SID 1 */
- h2n->swsi->http.ah = wsi->http.ah;
- h2n->swsi->client_mux_substream = 1;
- h2n->swsi->client_h2_alpn = 1;
- #if defined(LWS_WITH_CLIENT)
- h2n->swsi->flags = wsi->flags;
- #endif
- h2n->swsi->a.protocol = wsi->a.protocol;
- if (h2n->swsi->user_space &&
- !h2n->swsi->user_space_externally_allocated)
- lws_free(h2n->swsi->user_space);
- h2n->swsi->user_space = wsi->user_space;
- h2n->swsi->user_space_externally_allocated =
- wsi->user_space_externally_allocated;
- h2n->swsi->a.opaque_user_data = wsi->a.opaque_user_data;
- wsi->a.opaque_user_data = NULL;
- h2n->swsi->txc.manual_initial_tx_credit =
- wsi->txc.manual_initial_tx_credit;
- wsi->user_space = NULL;
- if (h2n->swsi->http.ah)
- h2n->swsi->http.ah->wsi = h2n->swsi;
- wsi->http.ah = NULL;
- lwsl_info("%s: MIGRATING nwsi %p: swsi %p\n", __func__,
- wsi, h2n->swsi);
- h2n->swsi->txc.tx_cr =
- h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
- lwsl_info("%s: initial tx credit on conn %p: %d\n",
- __func__, h2n->swsi, (int)h2n->swsi->txc.tx_cr);
- h2n->swsi->h2.initialized = 1;
- /* set our initial window size */
- if (!wsi->h2.initialized) {
- wsi->txc.tx_cr =
- h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
- lwsl_info("%s: initial tx credit for us to "
- "write on master %p: %d\n", __func__,
- wsi, (int)wsi->txc.tx_cr);
- wsi->h2.initialized = 1;
- }
- lws_callback_on_writable(h2n->swsi);
- if (!wsi->h2_acked_settings ||
- !(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM)
- ) {
- pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
- if (!pps)
- return 1;
- lws_pps_schedule(wsi, pps);
- lwsl_info("%s: SETTINGS ack PPS\n", __func__);
- wsi->h2_acked_settings = 1;
- }
- /* also attach any queued guys */
- lws_wsi_mux_apply_queue(wsi);
- }
- #endif
- break;
- case LWS_H2_FRAME_TYPE_CONTINUATION:
- case LWS_H2_FRAME_TYPE_HEADERS:
- if (!h2n->swsi)
- break;
- /* service the http request itself */
- if (h2n->last_action_dyntable_resize) {
- lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
- "dyntable resize last in headers");
- break;
- }
- if (!h2n->swsi->h2.END_HEADERS) {
- /* we are not finished yet */
- lwsl_info("witholding http action for continuation\n");
- h2n->cont_exp_sid = h2n->sid;
- h2n->cont_exp = 1;
- break;
- }
- /* confirm the hpack stream state is reasonable for finishing */
- if (h2n->hpack != HPKS_TYPE) {
- /* hpack incomplete */
- lwsl_info("hpack incomplete %d (type %d, len %u)\n",
- h2n->hpack, h2n->type,
- (unsigned int)h2n->hpack_len);
- lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
- "hpack incomplete");
- break;
- }
- /* this is the last part of HEADERS */
- switch (h2n->swsi->h2.h2_state) {
- case LWS_H2_STATE_IDLE:
- lws_h2_state(h2n->swsi, LWS_H2_STATE_OPEN);
- break;
- case LWS_H2_STATE_RESERVED_REMOTE:
- lws_h2_state(h2n->swsi, LWS_H2_STATE_HALF_CLOSED_LOCAL);
- break;
- }
- lwsl_info("http req, wsi=%p, h2n->swsi=%p\n", wsi, h2n->swsi);
- h2n->swsi->hdr_parsing_completed = 1;
- #if defined(LWS_WITH_CLIENT)
- if (h2n->swsi->client_mux_substream &&
- lws_client_interpret_server_handshake(h2n->swsi)) {
- lwsl_info("%s: cli int serv hs closed it\n", __func__);
- break;
- }
- #endif
- if (lws_hdr_extant(h2n->swsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
- const char *simp = lws_hdr_simple_ptr(h2n->swsi,
- WSI_TOKEN_HTTP_CONTENT_LENGTH);
- if (!simp) /* coverity */
- return 1;
- h2n->swsi->http.rx_content_length = atoll(simp);
- h2n->swsi->http.rx_content_remain =
- h2n->swsi->http.rx_content_length;
- lwsl_info("setting rx_content_length %lld\n",
- (long long)h2n->swsi->http.rx_content_length);
- }
- {
- int n = 0, len;
- char buf[256];
- const unsigned char *c;
- do {
- c = lws_token_to_string(n);
- if (!c) {
- n++;
- continue;
- }
- len = lws_hdr_total_length(h2n->swsi, n);
- if (!len || len > (int)sizeof(buf) - 1) {
- n++;
- continue;
- }
- if (lws_hdr_copy(h2n->swsi, buf, sizeof buf,
- n) < 0) {
- lwsl_info(" %s !oversize!\n",
- (char *)c);
- } else {
- buf[sizeof(buf) - 1] = '\0';
- lwsl_info(" %s = %s\n",
- (char *)c, buf);
- }
- n++;
- } while (c);
- }
- if (h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE ||
- h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED) {
- lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
- "Banning service on CLOSED_REMOTE");
- break;
- }
- switch (h2n->swsi->h2.h2_state) {
- case LWS_H2_STATE_IDLE:
- lws_h2_state(h2n->swsi, LWS_H2_STATE_OPEN);
- break;
- case LWS_H2_STATE_OPEN:
- if (h2n->swsi->h2.END_STREAM)
- lws_h2_state(h2n->swsi,
- LWS_H2_STATE_HALF_CLOSED_REMOTE);
- break;
- case LWS_H2_STATE_HALF_CLOSED_LOCAL:
- if (h2n->swsi->h2.END_STREAM)
- lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
- break;
- }
- #if defined(LWS_WITH_CLIENT)
- if (h2n->swsi->client_mux_substream) {
- lwsl_info("%s: wsi %p: headers: client path (h2 state %s)\n",
- __func__, wsi, h2_state_names[h2n->swsi->h2.h2_state]);
- break;
- }
- #endif
- if (!lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_PATH) ||
- !lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_METHOD) ||
- !lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_SCHEME) ||
- lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_STATUS) ||
- lws_hdr_extant(h2n->swsi, WSI_TOKEN_CONNECTION)) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "Pseudoheader checks");
- break;
- }
- if (lws_hdr_extant(h2n->swsi, WSI_TOKEN_TE)) {
- n = lws_hdr_total_length(h2n->swsi, WSI_TOKEN_TE);
- if (n != 8 ||
- !lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE) ||
- strncmp(lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE),
- "trailers", n)) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "Illegal transfer-encoding");
- break;
- }
- }
- #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
- lws_http_compression_validate(h2n->swsi);
- #endif
- #if defined(LWS_WITH_SERVER_STATUS)
- wsi->a.vhost->conn_stats.h2_trans++;
- #endif
- p = lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_HTTP_COLON_METHOD);
- /*
- * duplicate :path into the individual method uri header
- * index, so that it looks the same as h1 in the ah
- */
- for (n = 0; n < (int)LWS_ARRAY_SIZE(method_names); n++)
- if (p && !strcasecmp(p, method_names[n])) {
- h2n->swsi->http.ah->frag_index[method_index[n]] =
- h2n->swsi->http.ah->frag_index[
- WSI_TOKEN_HTTP_COLON_PATH];
- break;
- }
- lwsl_debug("%s: setting DEF_ACT from 0x%x\n", __func__,
- (unsigned int)h2n->swsi->wsistate);
- lwsi_set_state(h2n->swsi, LRS_DEFERRING_ACTION);
- lws_callback_on_writable(h2n->swsi);
- break;
- case LWS_H2_FRAME_TYPE_DATA:
- lwsl_info("%s: DATA flags 0x%x\n", __func__, h2n->flags);
- if (!h2n->swsi)
- break;
- if (lws_hdr_total_length(h2n->swsi,
- WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
- h2n->swsi->h2.END_STREAM &&
- h2n->swsi->http.rx_content_length &&
- h2n->swsi->http.rx_content_remain) {
- lws_h2_rst_stream(h2n->swsi, H2_ERR_PROTOCOL_ERROR,
- "Not enough rx content");
- break;
- }
- if (h2n->swsi->h2.END_STREAM &&
- h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN)
- lws_h2_state(h2n->swsi,
- LWS_H2_STATE_HALF_CLOSED_REMOTE);
- if (h2n->swsi->h2.END_STREAM &&
- h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_LOCAL)
- lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
- #if defined(LWS_WITH_CLIENT)
- /*
- * client... remote END_STREAM implies we weren't going to
- * send anything else anyway.
- */
- if (h2n->swsi->client_mux_substream &&
- (h2n->flags & LWS_H2_FLAG_END_STREAM)) {
- lwsl_info("%s: %p: DATA: end stream\n",
- __func__, h2n->swsi);
- if (h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN) {
- lws_h2_state(h2n->swsi,
- LWS_H2_STATE_HALF_CLOSED_REMOTE);
- // lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR,
- // "client done");
- // if (lws_http_transaction_completed_client(h2n->swsi))
- // lwsl_debug("tx completed returned close\n");
- }
- //if (h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_LOCAL)
- {
- lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
- lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR,
- "client done");
- if (lws_http_transaction_completed_client(h2n->swsi))
- lwsl_debug("tx completed returned close\n");
- }
- }
- #endif
- break;
- case LWS_H2_FRAME_TYPE_PING:
- if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)
- lws_validity_confirmed(wsi);
- else {
- /* they're sending us a ping request */
- struct lws_h2_protocol_send *pps =
- lws_h2_new_pps(LWS_H2_PPS_PONG);
- if (!pps)
- return 1;
- lwsl_info("rx ping, preparing pong\n");
- memcpy(pps->u.ping.ping_payload, h2n->ping_payload, 8);
- lws_pps_schedule(wsi, pps);
- }
- break;
- case LWS_H2_FRAME_TYPE_WINDOW_UPDATE:
- /*
- * We only have an unsigned 31-bit (positive) increment possible
- */
- h2n->hpack_e_dep &= ~(1u << 31);
- lwsl_info("WINDOW_UPDATE: sid %u %u (0x%x)\n",
- (unsigned int)h2n->sid,
- (unsigned int)h2n->hpack_e_dep,
- (unsigned int)h2n->hpack_e_dep);
- if (h2n->sid)
- eff_wsi = h2n->swsi;
- if (!eff_wsi) {
- if (h2n->sid > h2n->highest_sid_opened)
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "alien sid");
- break; /* ignore */
- }
- if (eff_wsi->a.vhost->options &
- LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW &&
- (uint64_t)eff_wsi->txc.tx_cr + (uint64_t)h2n->hpack_e_dep >
- (uint64_t)0x7fffffff)
- h2n->hpack_e_dep = 0x7fffffff - eff_wsi->txc.tx_cr;
- if ((uint64_t)eff_wsi->txc.tx_cr + (uint64_t)h2n->hpack_e_dep >
- (uint64_t)0x7fffffff) {
- if (h2n->sid)
- lws_h2_rst_stream(h2n->swsi,
- H2_ERR_FLOW_CONTROL_ERROR,
- "Flow control exceeded max");
- else
- lws_h2_goaway(wsi, H2_ERR_FLOW_CONTROL_ERROR,
- "Flow control exceeded max");
- break;
- }
- if (!h2n->hpack_e_dep) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "Zero length window update");
- break;
- }
- n = eff_wsi->txc.tx_cr;
- eff_wsi->txc.tx_cr += h2n->hpack_e_dep;
- lws_wsi_txc_report_manual_txcr_in(eff_wsi,
- (int32_t)h2n->hpack_e_dep);
- lws_wsi_txc_describe(&eff_wsi->txc, "WINDOW_UPDATE in",
- eff_wsi->mux.my_sid);
- if (n <= 0 && eff_wsi->txc.tx_cr <= 0)
- /* it helps, but won't change sendability for anyone */
- break;
- /*
- * It may have changed sendability (depends on SID 0 tx credit
- * too)... for us and any children waiting on us... reassess
- * blockage for all children first
- */
- lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) {
- lws_callback_on_writable(w);
- } lws_end_foreach_ll(w, mux.sibling_list);
- if (eff_wsi->txc.skint &&
- !lws_wsi_txc_check_skint(&eff_wsi->txc,
- lws_h2_tx_cr_get(eff_wsi)))
- /*
- * This one became un-skint, schedule a writeable
- * callback
- */
- lws_callback_on_writable(eff_wsi);
- break;
- case LWS_H2_FRAME_TYPE_GOAWAY:
- lwsl_notice("GOAWAY: last sid %u, error 0x%08X, string '%s'\n",
- (unsigned int)h2n->goaway_last_sid,
- (unsigned int)h2n->goaway_err, h2n->goaway_str);
- return 1;
- case LWS_H2_FRAME_TYPE_RST_STREAM:
- lwsl_info("LWS_H2_FRAME_TYPE_RST_STREAM: sid %u: reason 0x%x\n",
- (unsigned int)h2n->sid,
- (unsigned int)h2n->hpack_e_dep);
- break;
- case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */
- break;
- }
- return 0;
- }
- /*
- * This may want to send something on the network wsi, which may be in the
- * middle of a partial send. PPS sends are OK because they are queued to
- * go through the WRITABLE handler already.
- *
- * The read parser for the network wsi has no choice but to parse its stream
- * anyway, because otherwise it will not be able to get tx credit window
- * messages.
- *
- * Therefore if we will send non-PPS, ie, lws_http_action() for a stream
- * wsi, we must change its state and handle it as a priority in the
- * POLLOUT handler instead of writing it here.
- *
- * About closing... for the main network wsi, it should return nonzero to
- * close it all. If it needs to close an swsi, it can do it here.
- */
- int
- lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
- lws_filepos_t *inused)
- {
- struct lws_h2_netconn *h2n = wsi->h2.h2n;
- struct lws_h2_protocol_send *pps;
- unsigned char c, *oldin = in;
- int n, m;
- if (!h2n)
- goto fail;
- while (inlen--) {
- c = *in++;
- // lwsl_notice("%s: 0x%x\n", __func__, c);
- switch (lwsi_state(wsi)) {
- case LRS_H2_AWAIT_PREFACE:
- if (preface[h2n->count++] != c)
- goto fail;
- if (preface[h2n->count])
- break;
- lwsl_info("http2: %p: established\n", wsi);
- lwsi_set_state(wsi, LRS_H2_AWAIT_SETTINGS);
- lws_validity_confirmed(wsi);
- h2n->count = 0;
- wsi->txc.tx_cr = 65535;
- /*
- * we must send a settings frame -- empty one is OK...
- * that must be the first thing sent by server
- * and the peer must send a SETTINGS with ACK flag...
- */
- pps = lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS);
- if (!pps)
- goto fail;
- lws_pps_schedule(wsi, pps);
- break;
- case LRS_H2_WAITING_TO_SEND_HEADERS:
- case LRS_ESTABLISHED:
- case LRS_H2_AWAIT_SETTINGS:
- if (h2n->frame_state != LWS_H2_FRAME_HEADER_LENGTH)
- goto try_frame_start;
- /*
- * post-header, preamble / payload / padding part
- */
- h2n->count++;
- if (h2n->flags & LWS_H2_FLAG_PADDED &&
- !h2n->pad_length) {
- /*
- * Get the padding count... actual padding is
- * at the end of the frame.
- */
- h2n->padding = c;
- h2n->pad_length = 1;
- h2n->preamble++;
- if (h2n->padding > h2n->length - 1)
- lws_h2_goaway(wsi,
- H2_ERR_PROTOCOL_ERROR,
- "execssive padding");
- break; /* we consumed this */
- }
- if (h2n->flags & LWS_H2_FLAG_PRIORITY &&
- !h2n->collected_priority) {
- /* going to be 5 preamble bytes */
- lwsl_debug("PRIORITY FLAG: 0x%x\n", c);
- if (h2n->preamble++ - h2n->pad_length < 4) {
- h2n->dep = ((h2n->dep) << 8) | c;
- break; /* we consumed this */
- }
- h2n->weight_temp = c;
- h2n->collected_priority = 1;
- lwsl_debug("PRI FL: dep 0x%x, weight 0x%02X\n",
- (unsigned int)h2n->dep,
- h2n->weight_temp);
- break; /* we consumed this */
- }
- if (h2n->padding && h2n->count >
- (h2n->length - h2n->padding)) {
- if (c) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "nonzero padding");
- break;
- }
- goto frame_end;
- }
- /* applies to wsi->h2.swsi which may be wsi */
- switch(h2n->type) {
- case LWS_H2_FRAME_TYPE_SETTINGS:
- n = (h2n->count - 1 - h2n->preamble) %
- LWS_H2_SETTINGS_LEN;
- h2n->one_setting[n] = c;
- if (n != LWS_H2_SETTINGS_LEN - 1)
- break;
- lws_h2_settings(wsi, &h2n->peer_set,
- h2n->one_setting,
- LWS_H2_SETTINGS_LEN);
- break;
- case LWS_H2_FRAME_TYPE_CONTINUATION:
- case LWS_H2_FRAME_TYPE_HEADERS:
- if (!h2n->swsi)
- break;
- if (lws_hpack_interpret(h2n->swsi, c)) {
- lwsl_info("%s: hpack failed\n",
- __func__);
- goto fail;
- }
- break;
- case LWS_H2_FRAME_TYPE_GOAWAY:
- switch (h2n->inside++) {
- case 0:
- case 1:
- case 2:
- case 3:
- h2n->goaway_last_sid <<= 8;
- h2n->goaway_last_sid |= c;
- h2n->goaway_str[0] = '\0';
- break;
- case 4:
- case 5:
- case 6:
- case 7:
- h2n->goaway_err <<= 8;
- h2n->goaway_err |= c;
- break;
- default:
- if (h2n->inside - 9 <
- sizeof(h2n->goaway_str) - 1)
- h2n->goaway_str[
- h2n->inside - 9] = c;
- h2n->goaway_str[
- sizeof(h2n->goaway_str) - 1] = '\0';
- break;
- }
- break;
- case LWS_H2_FRAME_TYPE_DATA:
- lwsl_info("%s: LWS_H2_FRAME_TYPE_DATA: fl 0x%x\n",
- __func__, h2n->flags);
- /*
- * let the network wsi live a bit longer if
- * subs are active... our frame may take a long
- * time to chew through
- */
- if (!wsi->immortal_substream_count)
- lws_set_timeout(wsi,
- PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
- wsi->a.vhost->keepalive_timeout ?
- wsi->a.vhost->keepalive_timeout : 31);
- if (!h2n->swsi)
- break;
- if (lws_buflist_next_segment_len(
- &h2n->swsi->buflist, NULL))
- lwsl_info("%s: substream has pending\n",
- __func__);
- if (lwsi_role_http(h2n->swsi) &&
- lwsi_state(h2n->swsi) == LRS_ESTABLISHED) {
- lwsi_set_state(h2n->swsi, LRS_BODY);
- lwsl_info("%s: swsi %p to LRS_BODY\n",
- __func__, h2n->swsi);
- }
- if (lws_hdr_total_length(h2n->swsi,
- WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
- h2n->swsi->http.rx_content_length &&
- h2n->swsi->http.rx_content_remain <
- inlen + 1 && /* last */
- h2n->inside < h2n->length) {
- lwsl_warn("%s: rem %d, inlen %d\n",
- __func__,
- (int)h2n->swsi->http.rx_content_remain,
- (int)inlen + 1);
- /* unread data in frame */
- lws_h2_goaway(wsi,
- H2_ERR_PROTOCOL_ERROR,
- "More rx than content_length told");
- break;
- }
- /*
- * We operate on a frame. The RX we have at
- * hand may exceed the current frame.
- */
- n = (int)inlen + 1;
- if (n > (int)(h2n->length - h2n->count + 1)) {
- n = h2n->length - h2n->count + 1;
- lwsl_debug("---- restricting len to %d "
- "vs %ld\n", n, (long)inlen + 1);
- }
- #if defined(LWS_WITH_CLIENT)
- if (h2n->swsi->client_mux_substream) {
- if (!h2n->swsi->a.protocol) {
- lwsl_err("%s: swsi %p doesn't have protocol\n",
- __func__, h2n->swsi);
- m = 1;
- } else {
- h2n->swsi->txc.peer_tx_cr_est -= n;
- wsi->txc.peer_tx_cr_est -= n;
- lws_wsi_txc_describe(&h2n->swsi->txc,
- __func__,
- h2n->swsi->mux.my_sid);
- m = user_callback_handle_rxflow(
- h2n->swsi->a.protocol->callback,
- h2n->swsi,
- LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
- h2n->swsi->user_space,
- in - 1, n);
- }
- in += n - 1;
- h2n->inside += n;
- h2n->count += n - 1;
- inlen -= n - 1;
- if (m) {
- lwsl_info("RECEIVE_CLIENT_HTTP "
- "closed it\n");
- goto close_swsi_and_return;
- }
- break;
- }
- #endif
- if (lwsi_state(h2n->swsi) == LRS_DEFERRING_ACTION) {
- m = lws_buflist_append_segment(
- &h2n->swsi->buflist, in - 1, n);
- if (m < 0)
- return -1;
- if (m) {
- struct lws_context_per_thread *pt;
- pt = &wsi->a.context->pt[(int)wsi->tsi];
- lwsl_debug("%s: added %p to rxflow list\n",
- __func__, wsi);
- lws_dll2_add_head(
- &h2n->swsi->dll_buflist,
- &pt->dll_buflist_owner);
- }
- in += n - 1;
- h2n->inside += n;
- h2n->count += n - 1;
- inlen -= n - 1;
- lwsl_debug("%s: deferred %d\n", __func__, n);
- goto do_windows;
- }
- h2n->swsi->outer_will_close = 1;
- /*
- * choose the length for this go so that we end at
- * the frame boundary, in the case there is already
- * more waiting leave it for next time around
- */
- n = lws_read_h1(h2n->swsi, in - 1, n);
- // lwsl_notice("%s: lws_read_h1 %d\n", __func__, n);
- h2n->swsi->outer_will_close = 0;
- /*
- * can return 0 in POST body with
- * content len exhausted somehow.
- */
- if (n < 0 ||
- (!n && !lws_buflist_next_segment_len(
- &wsi->buflist, NULL))) {
- lwsl_info("%s: lws_read_h1 told %d %u / %u\n",
- __func__, n,
- (unsigned int)h2n->count,
- (unsigned int)h2n->length);
- in += h2n->length - h2n->count;
- h2n->inside = h2n->length;
- h2n->count = h2n->length - 1;
- //if (n < 0)
- // goto already_closed_swsi;
- goto close_swsi_and_return;
- }
- inlen -= n - 1;
- in += n - 1;
- h2n->inside += n;
- h2n->count += n - 1;
- h2n->swsi->txc.peer_tx_cr_est -= n;
- wsi->txc.peer_tx_cr_est -= n;
- do_windows:
- #if defined(LWS_WITH_CLIENT)
- if (!(h2n->swsi->flags & LCCSCF_H2_MANUAL_RXFLOW))
- #endif
- {
- /*
- * The default behaviour is we just keep
- * cranking the other side's tx credit
- * back up, for simple bulk transfer as
- * fast as we can take it
- */
- m = n; //(2 * h2n->length) + 65536;
- /* update both the stream and nwsi */
- lws_h2_update_peer_txcredit_thresh(h2n->swsi,
- h2n->sid, m, m);
- }
- #if defined(LWS_WITH_CLIENT)
- else {
- /*
- * If he's handling it himself, only
- * repair the nwsi credit but allow the
- * stream credit to run down until the
- * user code deals with it
- */
- lws_h2_update_peer_txcredit(wsi, 0, n);
- h2n->swsi->txc.manual = 1;
- }
- #endif
- break;
- case LWS_H2_FRAME_TYPE_PRIORITY:
- if (h2n->count <= 4) {
- h2n->dep <<= 8;
- h2n->dep |= c;
- break;
- }
- h2n->weight_temp = c;
- lwsl_info("PRIORITY: dep 0x%x, weight 0x%02X\n",
- (unsigned int)h2n->dep, h2n->weight_temp);
- if ((h2n->dep & ~(1u << 31)) == h2n->sid) {
- lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
- "cant depend on own sid");
- break;
- }
- break;
- case LWS_H2_FRAME_TYPE_RST_STREAM:
- h2n->hpack_e_dep <<= 8;
- h2n->hpack_e_dep |= c;
- break;
- case LWS_H2_FRAME_TYPE_PUSH_PROMISE:
- break;
- case LWS_H2_FRAME_TYPE_PING:
- if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK) { // ack
- } else { /* they're sending us a ping request */
- if (h2n->count > 8)
- return 1;
- h2n->ping_payload[h2n->count - 1] = c;
- }
- break;
- case LWS_H2_FRAME_TYPE_WINDOW_UPDATE:
- h2n->hpack_e_dep <<= 8;
- h2n->hpack_e_dep |= c;
- break;
- case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */
- break;
- default:
- lwsl_notice("%s: unhandled frame type %d\n",
- __func__, h2n->type);
- goto fail;
- }
- frame_end:
- if (h2n->count > h2n->length) {
- lwsl_notice("%s: count > length %u %u\n",
- __func__, (unsigned int)h2n->count,
- (unsigned int)h2n->length);
- goto fail;
- }
- if (h2n->count != h2n->length)
- break;
- /*
- * end of frame just happened
- */
- if (lws_h2_parse_end_of_frame(wsi))
- goto fail;
- break;
- try_frame_start:
- if (h2n->frame_state <= 8) {
- switch (h2n->frame_state++) {
- case 0:
- h2n->pad_length = 0;
- h2n->collected_priority = 0;
- h2n->padding = 0;
- h2n->preamble = 0;
- h2n->length = c;
- h2n->inside = 0;
- break;
- case 1:
- case 2:
- h2n->length <<= 8;
- h2n->length |= c;
- break;
- case 3:
- h2n->type = c;
- break;
- case 4:
- h2n->flags = c;
- break;
- case 5:
- case 6:
- case 7:
- case 8:
- h2n->sid <<= 8;
- h2n->sid |= c;
- break;
- }
- }
- if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH)
- if (lws_h2_parse_frame_header(wsi))
- goto fail;
- break;
- default:
- break;
- }
- }
- *inused = in - oldin;
- return 0;
- close_swsi_and_return:
- lws_close_free_wsi(h2n->swsi, 0, "close_swsi_and_return");
- h2n->swsi = NULL;
- h2n->frame_state = 0;
- h2n->count = 0;
- // already_closed_swsi:
- *inused = in - oldin;
- return 2;
- fail:
- *inused = in - oldin;
- return 1;
- }
- #if defined(LWS_WITH_CLIENT)
- int
- lws_h2_client_handshake(struct lws *wsi)
- {
- struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
- uint8_t *buf, *start, *p, *p1, *end;
- char *meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD),
- *uri = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), *simp;
- struct lws *nwsi = lws_get_network_wsi(wsi);
- int n, m;
- /*
- * The identifier of a newly established stream MUST be numerically
- * greater than all streams that the initiating endpoint has opened or
- * reserved. This governs streams that are opened using a HEADERS frame
- * and streams that are reserved using PUSH_PROMISE. An endpoint that
- * receives an unexpected stream identifier MUST respond with a
- * connection error (Section 5.4.1) of type PROTOCOL_ERROR.
- */
- int sid = nwsi->h2.h2n->highest_sid_opened + 2;
- lwsl_debug("%s\n", __func__);
- /*
- * We MUST allocate our sid here at the point we're about to send the
- * stream open. It's because we don't know the order in which multiple
- * open streams will send their headers... in h2, sending the headers
- * is the point the stream is opened. The peer requires that we only
- * open streams in ascending sid order
- */
- wsi->mux.my_sid = nwsi->h2.h2n->highest_sid_opened = sid;
- lwsl_info("%s: wsi %p: assigning SID %d at header send\n", __func__, wsi, sid);
- lwsl_info("%s: CLIENT_WAITING_TO_SEND_HEADERS: pollout (sid %d)\n",
- __func__, wsi->mux.my_sid);
- p = start = buf = pt->serv_buf + LWS_PRE;
- end = start + (wsi->a.context->pt_serv_buf_size / 2) - LWS_PRE - 1;
- /* it's time for us to send our client stream headers */
- if (!meth)
- meth = "GET";
- if (lws_add_http_header_by_token(wsi,
- WSI_TOKEN_HTTP_COLON_METHOD,
- (unsigned char *)meth,
- (int)strlen(meth), &p, end))
- goto fail_length;
- if (lws_add_http_header_by_token(wsi,
- WSI_TOKEN_HTTP_COLON_SCHEME,
- (unsigned char *)"https", 5,
- &p, end))
- goto fail_length;
- n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI);
- if (n && lws_add_http_header_by_token(wsi,
- WSI_TOKEN_HTTP_COLON_PATH,
- (unsigned char *)uri, n, &p, end))
- goto fail_length;
- n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
- simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
- if (n && simp && lws_add_http_header_by_token(wsi,
- WSI_TOKEN_HTTP_COLON_AUTHORITY,
- (unsigned char *)simp, n, &p, end))
- goto fail_length;
- n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_HOST);
- simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST);
- if (!wsi->client_h2_alpn && n && simp &&
- lws_add_http_header_by_token(wsi, WSI_TOKEN_HOST,
- (unsigned char *)simp, n, &p, end))
- goto fail_length;
- if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_USER_AGENT,
- (unsigned char *)"lwsss", 5,
- &p, end))
- goto fail_length;
- if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) {
- p1 = lws_http_multipart_headers(wsi, p);
- if (!p1)
- goto fail_length;
- p = p1;
- }
- if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED) {
- if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
- (unsigned char *)"application/x-www-form-urlencoded",
- 33, &p, end))
- goto fail_length;
- lws_client_http_body_pending(wsi, 1);
- }
- /* give userland a chance to append, eg, cookies */
- if (wsi->a.protocol->callback(wsi,
- LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
- wsi->user_space, &p, (end - p) - 12))
- goto fail_length;
- if (lws_finalize_http_header(wsi, &p, end))
- goto fail_length;
- #if defined(LWS_WITH_DETAILED_LATENCY)
- wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
- #endif
- m = LWS_WRITE_HTTP_HEADERS;
- #if defined(LWS_WITH_CLIENT)
- /* below is not needed in spec, indeed it destroys the long poll
- * feature, but required by nghttp2 */
- if ((wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) &&
- !(wsi->client_http_body_pending))
- m |= LWS_WRITE_H2_STREAM_END;
- #endif
- // lwsl_hexdump_notice(start, p - start);
- n = lws_write(wsi, start, p - start, m);
- if (n != (p - start)) {
- lwsl_err("_write returned %d from %ld\n", n,
- (long)(p - start));
- return -1;
- }
- /*
- * Normally let's charge up the peer tx credit a bit. But if
- * MANUAL_REFLOW is set, just set it to the initial credit given in
- * the client create info
- */
- n = 4 * 65536;
- if (wsi->flags & LCCSCF_H2_MANUAL_RXFLOW) {
- n = wsi->txc.manual_initial_tx_credit;
- wsi->txc.manual = 1;
- }
- if (lws_h2_update_peer_txcredit(wsi, wsi->mux.my_sid, n))
- return 1;
- lws_h2_state(wsi, LWS_H2_STATE_OPEN);
- lwsi_set_state(wsi, LRS_ESTABLISHED);
- if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME)
- lws_callback_on_writable(wsi);
- return 0;
- fail_length:
- lwsl_err("Client hdrs too long: incr context info.pt_serv_buf_size\n");
- return -1;
- }
- #endif
- #if defined(LWS_ROLE_WS) && defined(LWS_WITH_SERVER)
- int
- lws_h2_ws_handshake(struct lws *wsi)
- {
- uint8_t buf[LWS_PRE + 2048], *p = buf + LWS_PRE, *start = p,
- *end = &buf[sizeof(buf) - 1];
- const struct lws_http_mount *hit;
- const char * uri_ptr;
- int n, m;
- if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
- return -1;
- if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) > 64)
- return -1;
- if (wsi->proxied_ws_parent && wsi->child_list) {
- if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {
- if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
- (uint8_t *)lws_hdr_simple_ptr(wsi,
- WSI_TOKEN_PROTOCOL),
- (int)strlen(lws_hdr_simple_ptr(wsi,
- WSI_TOKEN_PROTOCOL)),
- &p, end))
- return -1;
- }
- } else {
- /* we can only return the protocol header if:
- * - one came in, and ... */
- if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) &&
- /* - it is not an empty string */
- wsi->a.protocol->name && wsi->a.protocol->name[0]) {
- #if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SERVER)
- /*
- * This is the h2 version of server-ws.c understanding that it
- * did the ws upgrade on a ss server object, therefore it needs
- * to pass back to the peer the policy ws-protocol name, not
- * the generic ss-ws.c protocol name
- */
- if (wsi->a.vhost && wsi->a.vhost->ss_handle &&
- wsi->a.vhost->ss_handle->policy->u.http.u.ws.subprotocol) {
- lws_ss_handle_t *h =
- (lws_ss_handle_t *)wsi->a.opaque_user_data;
- lwsl_notice("%s: Server SS %p .wsi %p switching to ws protocol\n",
- __func__, h, h->wsi);
- wsi->a.protocol = &protocol_secstream_ws;
- /*
- * inform the SS user code that this has done a one-way
- * upgrade to some other protocol... it will likely
- * want to treat subsequent payloads differently
- */
- lws_ss_event_helper(h, LWSSSCS_SERVER_UPGRADE);
- lws_mux_mark_immortal(wsi);
- if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
- (unsigned char *)wsi->a.vhost->ss_handle->policy->
- u.http.u.ws.subprotocol,
- (int)strlen(wsi->a.vhost->ss_handle->policy->
- u.http.u.ws.subprotocol), &p, end))
- return -1;
- } else
- #endif
- if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
- (unsigned char *)wsi->a.protocol->name,
- (int)strlen(wsi->a.protocol->name), &p, end))
- return -1;
- }
- }
- if (lws_finalize_http_header(wsi, &p, end))
- return -1;
- m = lws_ptr_diff(p, start);
- // lwsl_hexdump_notice(start, m);
- n = lws_write(wsi, start, m, LWS_WRITE_HTTP_HEADERS);
- if (n != m) {
- lwsl_err("_write returned %d from %d\n", n, m);
- return -1;
- }
- /*
- * alright clean up, set our state to generic ws established, the
- * mode / state of the nwsi will get the h2 processing done.
- */
- lwsi_set_state(wsi, LRS_ESTABLISHED);
- wsi->lws_rx_parse_state = 0; // ==LWS_RXPS_NEW;
- uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH);
- n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);
- hit = lws_find_mount(wsi, uri_ptr, n);
- if (hit && hit->cgienv &&
- wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO, wsi->user_space,
- (void *)hit->cgienv, 0))
- return 1;
- lws_validity_confirmed(wsi);
- return 0;
- }
- #endif
- int
- lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
- {
- unsigned char *oldbuf = buf;
- lws_filepos_t body_chunk_len;
- // lwsl_notice("%s: h2 path: wsistate 0x%x len %d\n", __func__,
- // wsi->wsistate, (int)len);
- /*
- * wsi here is always the network connection wsi, not a stream
- * wsi. Once we unpicked the framing we will find the right
- * swsi and make it the target of the frame.
- *
- * If it's ws over h2, the nwsi will get us here to do the h2
- * processing, and that will call us back with the swsi +
- * ESTABLISHED state for the inner payload, handled in a later
- * case.
- */
- while (len) {
- int m;
- /*
- * we were accepting input but now we stopped doing so
- */
- if (lws_is_flowcontrolled(wsi)) {
- lws_rxflow_cache(wsi, buf, 0, (int)len);
- buf += len;
- break;
- }
- /*
- * lws_h2_parser() may send something; when it gets the
- * whole frame, it will want to perform some action
- * involving a reply. But we may be in a partial send
- * situation on the network wsi...
- *
- * Even though we may be in a partial send and unable to
- * send anything new, we still have to parse the network
- * wsi in order to gain tx credit to send, which is
- * potentially necessary to clear the old partial send.
- *
- * ALL network wsi-specific frames are sent by PPS
- * already, these are sent as a priority on the writable
- * handler, and so respect partial sends. The only
- * problem is when a stream wsi wants to send an, eg,
- * reply headers frame in response to the parsing
- * we will do now... the *stream wsi* must stall in a
- * different state until it is able to do so from a
- * priority on the WRITABLE callback, same way that
- * file transfers operate.
- */
- m = lws_h2_parser(wsi, buf, len, &body_chunk_len);
- if (m && m != 2) {
- lwsl_debug("%s: http2_parser bail: %d\n", __func__, m);
- lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "lws_read_h2 bail");
- return -1;
- }
- if (m == 2) {
- /* swsi has been closed */
- buf += body_chunk_len;
- break;
- }
- buf += body_chunk_len;
- len -= body_chunk_len;
- }
- return lws_ptr_diff(buf, oldbuf);
- }
- int
- lws_h2_client_stream_long_poll_rxonly(struct lws *wsi)
- {
- if (!wsi->mux_substream)
- return 1;
- /*
- * Elect to send an empty DATA with END_STREAM, to force the stream
- * into HALF_CLOSED LOCAL
- */
- wsi->h2.long_poll = 1;
- wsi->h2.send_END_STREAM = 1;
- // lws_header_table_detach(wsi, 0);
- lws_callback_on_writable(wsi);
- return 0;
- }
|