1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132 |
- #include "http_parser.h"
- #include <stdlib.h>
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h> /* rand */
- #include <string.h>
- #include <stdarg.h>
- #if defined(__APPLE__)
- # undef strlcat
- # undef strlncpy
- # undef strlcpy
- #endif
- #undef TRUE
- #define TRUE 1
- #undef FALSE
- #define FALSE 0
- #define MAX_HEADERS 13
- #define MAX_ELEMENT_SIZE 2048
- #define MAX_CHUNKS 16
- #define MIN(a,b) ((a) < (b) ? (a) : (b))
- static http_parser *parser;
- struct message {
- const char *name;
- const char *raw;
- enum http_parser_type type;
- enum http_method method;
- int status_code;
- char response_status[MAX_ELEMENT_SIZE];
- char request_path[MAX_ELEMENT_SIZE];
- char request_url[MAX_ELEMENT_SIZE];
- char fragment[MAX_ELEMENT_SIZE];
- char query_string[MAX_ELEMENT_SIZE];
- char body[MAX_ELEMENT_SIZE];
- size_t body_size;
- const char *host;
- const char *userinfo;
- uint16_t port;
- int num_headers;
- enum { NONE=0, FIELD, VALUE } last_header_element;
- char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
- int should_keep_alive;
- int num_chunks;
- int num_chunks_complete;
- int chunk_lengths[MAX_CHUNKS];
- const char *upgrade;
- unsigned short http_major;
- unsigned short http_minor;
- int message_begin_cb_called;
- int headers_complete_cb_called;
- int message_complete_cb_called;
- int message_complete_on_eof;
- int body_is_final;
- };
- static int currently_parsing_eof;
- static struct message messages[5];
- static int num_messages;
- static http_parser_settings *current_pause_parser;
- const struct message requests[] =
- #define CURL_GET 0
- { {.name= "curl get"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /test HTTP/1.1\r\n"
- "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n"
- "Host: 0.0.0.0=5000\r\n"
- "Accept: */*\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/test"
- ,.request_url= "/test"
- ,.num_headers= 3
- ,.headers=
- { { "User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1" }
- , { "Host", "0.0.0.0=5000" }
- , { "Accept", "*/*" }
- }
- ,.body= ""
- }
- #define FIREFOX_GET 1
- , {.name= "firefox get"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /favicon.ico HTTP/1.1\r\n"
- "Host: 0.0.0.0=5000\r\n"
- "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"
- "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
- "Accept-Language: en-us,en;q=0.5\r\n"
- "Accept-Encoding: gzip,deflate\r\n"
- "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
- "Keep-Alive: 300\r\n"
- "Connection: keep-alive\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/favicon.ico"
- ,.request_url= "/favicon.ico"
- ,.num_headers= 8
- ,.headers=
- { { "Host", "0.0.0.0=5000" }
- , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" }
- , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" }
- , { "Accept-Language", "en-us,en;q=0.5" }
- , { "Accept-Encoding", "gzip,deflate" }
- , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" }
- , { "Keep-Alive", "300" }
- , { "Connection", "keep-alive" }
- }
- ,.body= ""
- }
- #define DUMBFUCK 2
- , {.name= "dumbfuck"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /dumbfuck HTTP/1.1\r\n"
- "aaaaaaaaaaaaa:++++++++++\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/dumbfuck"
- ,.request_url= "/dumbfuck"
- ,.num_headers= 1
- ,.headers=
- { { "aaaaaaaaaaaaa", "++++++++++" }
- }
- ,.body= ""
- }
- #define FRAGMENT_IN_URI 3
- , {.name= "fragment in url"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= "page=1"
- ,.fragment= "posts-17408"
- ,.request_path= "/forums/1/topics/2375"
-
- ,.request_url= "/forums/1/topics/2375?page=1#posts-17408"
- ,.num_headers= 0
- ,.body= ""
- }
- #define GET_NO_HEADERS_NO_BODY 4
- , {.name= "get no headers no body"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/get_no_headers_no_body/world"
- ,.request_url= "/get_no_headers_no_body/world"
- ,.num_headers= 0
- ,.body= ""
- }
- #define GET_ONE_HEADER_NO_BODY 5
- , {.name= "get one header no body"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n"
- "Accept: */*\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/get_one_header_no_body"
- ,.request_url= "/get_one_header_no_body"
- ,.num_headers= 1
- ,.headers=
- { { "Accept" , "*/*" }
- }
- ,.body= ""
- }
- #define GET_FUNKY_CONTENT_LENGTH 6
- , {.name= "get funky content length body hello"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n"
- "conTENT-Length: 5\r\n"
- "\r\n"
- "HELLO"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/get_funky_content_length_body_hello"
- ,.request_url= "/get_funky_content_length_body_hello"
- ,.num_headers= 1
- ,.headers=
- { { "conTENT-Length" , "5" }
- }
- ,.body= "HELLO"
- }
- #define POST_IDENTITY_BODY_WORLD 7
- , {.name= "post identity body world"
- ,.type= HTTP_REQUEST
- ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n"
- "Accept: */*\r\n"
- "Transfer-Encoding: identity\r\n"
- "Content-Length: 5\r\n"
- "\r\n"
- "World"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_POST
- ,.query_string= "q=search"
- ,.fragment= "hey"
- ,.request_path= "/post_identity_body_world"
- ,.request_url= "/post_identity_body_world?q=search#hey"
- ,.num_headers= 3
- ,.headers=
- { { "Accept", "*/*" }
- , { "Transfer-Encoding", "identity" }
- , { "Content-Length", "5" }
- }
- ,.body= "World"
- }
- #define POST_CHUNKED_ALL_YOUR_BASE 8
- , {.name= "post - chunked body: all your base are belong to us"
- ,.type= HTTP_REQUEST
- ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n"
- "Transfer-Encoding: chunked\r\n"
- "\r\n"
- "1e\r\nall your base are belong to us\r\n"
- "0\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_POST
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/post_chunked_all_your_base"
- ,.request_url= "/post_chunked_all_your_base"
- ,.num_headers= 1
- ,.headers=
- { { "Transfer-Encoding" , "chunked" }
- }
- ,.body= "all your base are belong to us"
- ,.num_chunks_complete= 2
- ,.chunk_lengths= { 0x1e }
- }
- #define TWO_CHUNKS_MULT_ZERO_END 9
- , {.name= "two chunks ; triple zero ending"
- ,.type= HTTP_REQUEST
- ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n"
- "Transfer-Encoding: chunked\r\n"
- "\r\n"
- "5\r\nhello\r\n"
- "6\r\n world\r\n"
- "000\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_POST
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/two_chunks_mult_zero_end"
- ,.request_url= "/two_chunks_mult_zero_end"
- ,.num_headers= 1
- ,.headers=
- { { "Transfer-Encoding", "chunked" }
- }
- ,.body= "hello world"
- ,.num_chunks_complete= 3
- ,.chunk_lengths= { 5, 6 }
- }
- #define CHUNKED_W_TRAILING_HEADERS 10
- , {.name= "chunked with trailing headers. blech."
- ,.type= HTTP_REQUEST
- ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n"
- "Transfer-Encoding: chunked\r\n"
- "\r\n"
- "5\r\nhello\r\n"
- "6\r\n world\r\n"
- "0\r\n"
- "Vary: *\r\n"
- "Content-Type: text/plain\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_POST
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/chunked_w_trailing_headers"
- ,.request_url= "/chunked_w_trailing_headers"
- ,.num_headers= 3
- ,.headers=
- { { "Transfer-Encoding", "chunked" }
- , { "Vary", "*" }
- , { "Content-Type", "text/plain" }
- }
- ,.body= "hello world"
- ,.num_chunks_complete= 3
- ,.chunk_lengths= { 5, 6 }
- }
- #define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
- , {.name= "with bullshit after the length"
- ,.type= HTTP_REQUEST
- ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
- "Transfer-Encoding: chunked\r\n"
- "\r\n"
- "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n"
- "6; blahblah; blah\r\n world\r\n"
- "0\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_POST
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/chunked_w_bullshit_after_length"
- ,.request_url= "/chunked_w_bullshit_after_length"
- ,.num_headers= 1
- ,.headers=
- { { "Transfer-Encoding", "chunked" }
- }
- ,.body= "hello world"
- ,.num_chunks_complete= 3
- ,.chunk_lengths= { 5, 6 }
- }
- #define WITH_QUOTES 12
- , {.name= "with quotes"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= "foo=\"bar\""
- ,.fragment= ""
- ,.request_path= "/with_\"stupid\"_quotes"
- ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\""
- ,.num_headers= 0
- ,.headers= { }
- ,.body= ""
- }
- #define APACHEBENCH_GET 13
- , {.name = "apachebench get"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /test HTTP/1.0\r\n"
- "Host: 0.0.0.0:5000\r\n"
- "User-Agent: ApacheBench/2.3\r\n"
- "Accept: */*\r\n\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/test"
- ,.request_url= "/test"
- ,.num_headers= 3
- ,.headers= { { "Host", "0.0.0.0:5000" }
- , { "User-Agent", "ApacheBench/2.3" }
- , { "Accept", "*/*" }
- }
- ,.body= ""
- }
- #define QUERY_URL_WITH_QUESTION_MARK_GET 14
- , {.name = "query url with question mark"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= "foo=bar?baz"
- ,.fragment= ""
- ,.request_path= "/test.cgi"
- ,.request_url= "/test.cgi?foo=bar?baz"
- ,.num_headers= 0
- ,.headers= {}
- ,.body= ""
- }
- #define PREFIX_NEWLINE_GET 15
- , {.name = "newline prefix get"
- ,.type= HTTP_REQUEST
- ,.raw= "\r\nGET /test HTTP/1.1\r\n\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/test"
- ,.request_url= "/test"
- ,.num_headers= 0
- ,.headers= { }
- ,.body= ""
- }
- #define UPGRADE_REQUEST 16
- , {.name = "upgrade request"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Upgrade: WebSocket\r\n"
- "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
- "Origin: http://example.com\r\n"
- "\r\n"
- "Hot diggity dogg"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/demo"
- ,.request_url= "/demo"
- ,.num_headers= 7
- ,.upgrade="Hot diggity dogg"
- ,.headers= { { "Host", "example.com" }
- , { "Connection", "Upgrade" }
- , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
- , { "Sec-WebSocket-Protocol", "sample" }
- , { "Upgrade", "WebSocket" }
- , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
- , { "Origin", "http://example.com" }
- }
- ,.body= ""
- }
- #define CONNECT_REQUEST 17
- , {.name = "connect request"
- ,.type= HTTP_REQUEST
- ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
- "User-agent: Mozilla/1.1N\r\n"
- "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
- "\r\n"
- "some data\r\n"
- "and yet even more data"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.method= HTTP_CONNECT
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= ""
- ,.request_url= "0-home0.netscape.com:443"
- ,.num_headers= 2
- ,.upgrade="some data\r\nand yet even more data"
- ,.headers= { { "User-agent", "Mozilla/1.1N" }
- , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
- }
- ,.body= ""
- }
- #define REPORT_REQ 18
- , {.name= "report request"
- ,.type= HTTP_REQUEST
- ,.raw= "REPORT /test HTTP/1.1\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_REPORT
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/test"
- ,.request_url= "/test"
- ,.num_headers= 0
- ,.headers= {}
- ,.body= ""
- }
- #define NO_HTTP_VERSION 19
- , {.name= "request with no http version"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 0
- ,.http_minor= 9
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/"
- ,.request_url= "/"
- ,.num_headers= 0
- ,.headers= {}
- ,.body= ""
- }
- #define MSEARCH_REQ 20
- , {.name= "m-search request"
- ,.type= HTTP_REQUEST
- ,.raw= "M-SEARCH * HTTP/1.1\r\n"
- "HOST: 239.255.255.250:1900\r\n"
- "MAN: \"ssdp:discover\"\r\n"
- "ST: \"ssdp:all\"\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_MSEARCH
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "*"
- ,.request_url= "*"
- ,.num_headers= 3
- ,.headers= { { "HOST", "239.255.255.250:1900" }
- , { "MAN", "\"ssdp:discover\"" }
- , { "ST", "\"ssdp:all\"" }
- }
- ,.body= ""
- }
- #define LINE_FOLDING_IN_HEADER 21
- , {.name= "line folding in header value"
- ,.type= HTTP_REQUEST
- ,.raw= "GET / HTTP/1.1\r\n"
- "Line1: abc\r\n"
- "\tdef\r\n"
- " ghi\r\n"
- "\t\tjkl\r\n"
- " mno \r\n"
- "\t \tqrs\r\n"
- "Line2: \t line2\t\r\n"
- "Line3:\r\n"
- " line3\r\n"
- "Line4: \r\n"
- " \r\n"
- "Connection:\r\n"
- " close\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/"
- ,.request_url= "/"
- ,.num_headers= 5
- ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
- , { "Line2", "line2\t" }
- , { "Line3", "line3" }
- , { "Line4", "" }
- , { "Connection", "close" },
- }
- ,.body= ""
- }
- #define QUERY_TERMINATED_HOST 22
- , {.name= "host terminated by a query string"
- ,.type= HTTP_REQUEST
- ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= "hail=all"
- ,.fragment= ""
- ,.request_path= ""
- ,.request_url= "http://hypnotoad.org?hail=all"
- ,.host= "hypnotoad.org"
- ,.num_headers= 0
- ,.headers= { }
- ,.body= ""
- }
- #define QUERY_TERMINATED_HOSTPORT 23
- , {.name= "host:port terminated by a query string"
- ,.type= HTTP_REQUEST
- ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= "hail=all"
- ,.fragment= ""
- ,.request_path= ""
- ,.request_url= "http://hypnotoad.org:1234?hail=all"
- ,.host= "hypnotoad.org"
- ,.port= 1234
- ,.num_headers= 0
- ,.headers= { }
- ,.body= ""
- }
- #define SPACE_TERMINATED_HOSTPORT 24
- , {.name= "host:port terminated by a space"
- ,.type= HTTP_REQUEST
- ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= ""
- ,.request_url= "http://hypnotoad.org:1234"
- ,.host= "hypnotoad.org"
- ,.port= 1234
- ,.num_headers= 0
- ,.headers= { }
- ,.body= ""
- }
- #define PATCH_REQ 25
- , {.name = "PATCH request"
- ,.type= HTTP_REQUEST
- ,.raw= "PATCH /file.txt HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Content-Type: application/example\r\n"
- "If-Match: \"e0023aa4e\"\r\n"
- "Content-Length: 10\r\n"
- "\r\n"
- "cccccccccc"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_PATCH
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/file.txt"
- ,.request_url= "/file.txt"
- ,.num_headers= 4
- ,.headers= { { "Host", "www.example.com" }
- , { "Content-Type", "application/example" }
- , { "If-Match", "\"e0023aa4e\"" }
- , { "Content-Length", "10" }
- }
- ,.body= "cccccccccc"
- }
- #define CONNECT_CAPS_REQUEST 26
- , {.name = "connect caps request"
- ,.type= HTTP_REQUEST
- ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
- "User-agent: Mozilla/1.1N\r\n"
- "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.method= HTTP_CONNECT
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= ""
- ,.request_url= "HOME0.NETSCAPE.COM:443"
- ,.num_headers= 2
- ,.upgrade=""
- ,.headers= { { "User-agent", "Mozilla/1.1N" }
- , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
- }
- ,.body= ""
- }
- #if !HTTP_PARSER_STRICT
- #define UTF8_PATH_REQ 27
- , {.name= "utf-8 path request"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
- "Host: github.com\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= "q=1"
- ,.fragment= "narf"
- ,.request_path= "/δ¶/δt/pope"
- ,.request_url= "/δ¶/δt/pope?q=1#narf"
- ,.num_headers= 1
- ,.headers= { {"Host", "github.com" }
- }
- ,.body= ""
- }
- #define HOSTNAME_UNDERSCORE 28
- , {.name = "hostname underscore"
- ,.type= HTTP_REQUEST
- ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
- "User-agent: Mozilla/1.1N\r\n"
- "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.method= HTTP_CONNECT
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= ""
- ,.request_url= "home_0.netscape.com:443"
- ,.num_headers= 2
- ,.upgrade=""
- ,.headers= { { "User-agent", "Mozilla/1.1N" }
- , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
- }
- ,.body= ""
- }
- #endif
- #define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
- , {.name = "eat CRLF between requests, no \"Connection: close\" header"
- ,.raw= "POST / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "Content-Length: 4\r\n"
- "\r\n"
- "q=42\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_POST
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/"
- ,.request_url= "/"
- ,.num_headers= 3
- ,.upgrade= 0
- ,.headers= { { "Host", "www.example.com" }
- , { "Content-Type", "application/x-www-form-urlencoded" }
- , { "Content-Length", "4" }
- }
- ,.body= "q=42"
- }
- #define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
- , {.name = "eat CRLF between requests even if \"Connection: close\" is set"
- ,.raw= "POST / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "Content-Length: 4\r\n"
- "Connection: close\r\n"
- "\r\n"
- "q=42\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_POST
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/"
- ,.request_url= "/"
- ,.num_headers= 4
- ,.upgrade= 0
- ,.headers= { { "Host", "www.example.com" }
- , { "Content-Type", "application/x-www-form-urlencoded" }
- , { "Content-Length", "4" }
- , { "Connection", "close" }
- }
- ,.body= "q=42"
- }
- #define PURGE_REQ 31
- , {.name = "PURGE request"
- ,.type= HTTP_REQUEST
- ,.raw= "PURGE /file.txt HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_PURGE
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/file.txt"
- ,.request_url= "/file.txt"
- ,.num_headers= 1
- ,.headers= { { "Host", "www.example.com" } }
- ,.body= ""
- }
- #define SEARCH_REQ 32
- , {.name = "SEARCH request"
- ,.type= HTTP_REQUEST
- ,.raw= "SEARCH / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_SEARCH
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/"
- ,.request_url= "/"
- ,.num_headers= 1
- ,.headers= { { "Host", "www.example.com" } }
- ,.body= ""
- }
- #define PROXY_WITH_BASIC_AUTH 33
- , {.name= "host:port and basic_auth"
- ,.type= HTTP_REQUEST
- ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.fragment= ""
- ,.request_path= "/toto"
- ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
- ,.host= "hypnotoad.org"
- ,.userinfo= "a%12:b!&*$"
- ,.port= 1234
- ,.num_headers= 0
- ,.headers= { }
- ,.body= ""
- }
- #define LINE_FOLDING_IN_HEADER_WITH_LF 34
- , {.name= "line folding in header value"
- ,.type= HTTP_REQUEST
- ,.raw= "GET / HTTP/1.1\n"
- "Line1: abc\n"
- "\tdef\n"
- " ghi\n"
- "\t\tjkl\n"
- " mno \n"
- "\t \tqrs\n"
- "Line2: \t line2\t\n"
- "Line3:\n"
- " line3\n"
- "Line4: \n"
- " \n"
- "Connection:\n"
- " close\n"
- "\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/"
- ,.request_url= "/"
- ,.num_headers= 5
- ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
- , { "Line2", "line2\t" }
- , { "Line3", "line3" }
- , { "Line4", "" }
- , { "Connection", "close" },
- }
- ,.body= ""
- }
- #define CONNECTION_MULTI 35
- , {.name = "multiple connection header values with folding"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Connection: Something,\r\n"
- " Upgrade, ,Keep-Alive\r\n"
- "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Upgrade: WebSocket\r\n"
- "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
- "Origin: http://example.com\r\n"
- "\r\n"
- "Hot diggity dogg"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/demo"
- ,.request_url= "/demo"
- ,.num_headers= 7
- ,.upgrade="Hot diggity dogg"
- ,.headers= { { "Host", "example.com" }
- , { "Connection", "Something, Upgrade, ,Keep-Alive" }
- , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
- , { "Sec-WebSocket-Protocol", "sample" }
- , { "Upgrade", "WebSocket" }
- , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
- , { "Origin", "http://example.com" }
- }
- ,.body= ""
- }
- #define CONNECTION_MULTI_LWS 36
- , {.name = "multiple connection header values with folding and lws"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /demo HTTP/1.1\r\n"
- "Connection: keep-alive, upgrade\r\n"
- "Upgrade: WebSocket\r\n"
- "\r\n"
- "Hot diggity dogg"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/demo"
- ,.request_url= "/demo"
- ,.num_headers= 2
- ,.upgrade="Hot diggity dogg"
- ,.headers= { { "Connection", "keep-alive, upgrade" }
- , { "Upgrade", "WebSocket" }
- }
- ,.body= ""
- }
- #define CONNECTION_MULTI_LWS_CRLF 37
- , {.name = "multiple connection header values with folding and lws"
- ,.type= HTTP_REQUEST
- ,.raw= "GET /demo HTTP/1.1\r\n"
- "Connection: keep-alive, \r\n upgrade\r\n"
- "Upgrade: WebSocket\r\n"
- "\r\n"
- "Hot diggity dogg"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_GET
- ,.query_string= ""
- ,.fragment= ""
- ,.request_path= "/demo"
- ,.request_url= "/demo"
- ,.num_headers= 2
- ,.upgrade="Hot diggity dogg"
- ,.headers= { { "Connection", "keep-alive, upgrade" }
- , { "Upgrade", "WebSocket" }
- }
- ,.body= ""
- }
- #define UPGRADE_POST_REQUEST 38
- , {.name = "upgrade post request"
- ,.type= HTTP_REQUEST
- ,.raw= "POST /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Connection: Upgrade\r\n"
- "Upgrade: HTTP/2.0\r\n"
- "Content-Length: 15\r\n"
- "\r\n"
- "sweet post body"
- "Hot diggity dogg"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_POST
- ,.request_path= "/demo"
- ,.request_url= "/demo"
- ,.num_headers= 4
- ,.upgrade="Hot diggity dogg"
- ,.headers= { { "Host", "example.com" }
- , { "Connection", "Upgrade" }
- , { "Upgrade", "HTTP/2.0" }
- , { "Content-Length", "15" }
- }
- ,.body= "sweet post body"
- }
- #define CONNECT_WITH_BODY_REQUEST 39
- , {.name = "connect with body request"
- ,.type= HTTP_REQUEST
- ,.raw= "CONNECT foo.bar.com:443 HTTP/1.0\r\n"
- "User-agent: Mozilla/1.1N\r\n"
- "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
- "Content-Length: 10\r\n"
- "\r\n"
- "blarfcicle"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.method= HTTP_CONNECT
- ,.request_url= "foo.bar.com:443"
- ,.num_headers= 3
- ,.upgrade="blarfcicle"
- ,.headers= { { "User-agent", "Mozilla/1.1N" }
- , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
- , { "Content-Length", "10" }
- }
- ,.body= ""
- }
- #define LINK_REQUEST 40
- , {.name = "link request"
- ,.type= HTTP_REQUEST
- ,.raw= "LINK /images/my_dog.jpg HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Link: <http://example.com/profiles/joe>; rel=\"tag\"\r\n"
- "Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_LINK
- ,.request_path= "/images/my_dog.jpg"
- ,.request_url= "/images/my_dog.jpg"
- ,.query_string= ""
- ,.fragment= ""
- ,.num_headers= 3
- ,.headers= { { "Host", "example.com" }
- , { "Link", "<http://example.com/profiles/joe>; rel=\"tag\"" }
- , { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
- }
- ,.body= ""
- }
- #define UNLINK_REQUEST 41
- , {.name = "link request"
- ,.type= HTTP_REQUEST
- ,.raw= "UNLINK /images/my_dog.jpg HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.method= HTTP_UNLINK
- ,.request_path= "/images/my_dog.jpg"
- ,.request_url= "/images/my_dog.jpg"
- ,.query_string= ""
- ,.fragment= ""
- ,.num_headers= 2
- ,.headers= { { "Host", "example.com" }
- , { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
- }
- ,.body= ""
- }
- , {.name= NULL }
- };
- const struct message responses[] =
- #define GOOGLE_301 0
- { {.name= "google 301"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 301 Moved Permanently\r\n"
- "Location: http://www.google.com/\r\n"
- "Content-Type: text/html; charset=UTF-8\r\n"
- "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
- "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
- "X-$PrototypeBI-Version: 1.6.0.3\r\n"
- "Cache-Control: public, max-age=2592000\r\n"
- "Server: gws\r\n"
- "Content-Length: 219 \r\n"
- "\r\n"
- "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
- "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
- "<H1>301 Moved</H1>\n"
- "The document has moved\n"
- "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
- "</BODY></HTML>\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 301
- ,.response_status= "Moved Permanently"
- ,.num_headers= 8
- ,.headers=
- { { "Location", "http://www.google.com/" }
- , { "Content-Type", "text/html; charset=UTF-8" }
- , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" }
- , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" }
- , { "X-$PrototypeBI-Version", "1.6.0.3" }
- , { "Cache-Control", "public, max-age=2592000" }
- , { "Server", "gws" }
- , { "Content-Length", "219 " }
- }
- ,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
- "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
- "<H1>301 Moved</H1>\n"
- "The document has moved\n"
- "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
- "</BODY></HTML>\r\n"
- }
- #define NO_CONTENT_LENGTH_RESPONSE 1
- , {.name= "no content-length response"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n"
- "Server: Apache\r\n"
- "X-Powered-By: Servlet/2.5 JSP/2.1\r\n"
- "Content-Type: text/xml; charset=utf-8\r\n"
- "Connection: close\r\n"
- "\r\n"
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
- " <SOAP-ENV:Body>\n"
- " <SOAP-ENV:Fault>\n"
- " <faultcode>SOAP-ENV:Client</faultcode>\n"
- " <faultstring>Client Error</faultstring>\n"
- " </SOAP-ENV:Fault>\n"
- " </SOAP-ENV:Body>\n"
- "</SOAP-ENV:Envelope>"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 5
- ,.headers=
- { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
- , { "Server", "Apache" }
- , { "X-Powered-By", "Servlet/2.5 JSP/2.1" }
- , { "Content-Type", "text/xml; charset=utf-8" }
- , { "Connection", "close" }
- }
- ,.body= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
- " <SOAP-ENV:Body>\n"
- " <SOAP-ENV:Fault>\n"
- " <faultcode>SOAP-ENV:Client</faultcode>\n"
- " <faultstring>Client Error</faultstring>\n"
- " </SOAP-ENV:Fault>\n"
- " </SOAP-ENV:Body>\n"
- "</SOAP-ENV:Envelope>"
- }
- #define NO_HEADERS_NO_BODY_404 2
- , {.name= "404 no headers no body"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 404
- ,.response_status= "Not Found"
- ,.num_headers= 0
- ,.headers= {}
- ,.body_size= 0
- ,.body= ""
- }
- #define NO_REASON_PHRASE 3
- , {.name= "301 no response phrase"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 301\r\n\r\n"
- ,.should_keep_alive = FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 301
- ,.response_status= ""
- ,.num_headers= 0
- ,.headers= {}
- ,.body= ""
- }
- #define TRAILING_SPACE_ON_CHUNKED_BODY 4
- , {.name="200 trailing space on chunked body"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/plain\r\n"
- "Transfer-Encoding: chunked\r\n"
- "\r\n"
- "25 \r\n"
- "This is the data in the first chunk\r\n"
- "\r\n"
- "1C\r\n"
- "and this is the second one\r\n"
- "\r\n"
- "0 \r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 2
- ,.headers=
- { {"Content-Type", "text/plain" }
- , {"Transfer-Encoding", "chunked" }
- }
- ,.body_size = 37+28
- ,.body =
- "This is the data in the first chunk\r\n"
- "and this is the second one\r\n"
- ,.num_chunks_complete= 3
- ,.chunk_lengths= { 0x25, 0x1c }
- }
- #define NO_CARRIAGE_RET 5
- , {.name="no carriage ret"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\n"
- "Content-Type: text/html; charset=utf-8\n"
- "Connection: close\n"
- "\n"
- "these headers are from http://news.ycombinator.com/"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 2
- ,.headers=
- { {"Content-Type", "text/html; charset=utf-8" }
- , {"Connection", "close" }
- }
- ,.body= "these headers are from http://news.ycombinator.com/"
- }
- #define PROXY_CONNECTION 6
- , {.name="proxy connection"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=UTF-8\r\n"
- "Content-Length: 11\r\n"
- "Proxy-Connection: close\r\n"
- "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n"
- "\r\n"
- "hello world"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 4
- ,.headers=
- { {"Content-Type", "text/html; charset=UTF-8" }
- , {"Content-Length", "11" }
- , {"Proxy-Connection", "close" }
- , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"}
- }
- ,.body= "hello world"
- }
- #define UNDERSTORE_HEADER_KEY 7
-
-
- , {.name="underscore header key"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "Server: DCLK-AdSvr\r\n"
- "Content-Type: text/xml\r\n"
- "Content-Length: 0\r\n"
- "DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 4
- ,.headers=
- { {"Server", "DCLK-AdSvr" }
- , {"Content-Type", "text/xml" }
- , {"Content-Length", "0" }
- , {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" }
- }
- ,.body= ""
- }
- #define BONJOUR_MADAME_FR 8
- , {.name= "bonjourmadame.fr"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.0 301 Moved Permanently\r\n"
- "Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n"
- "Server: Apache/2.2.3 (Red Hat)\r\n"
- "Cache-Control: public\r\n"
- "Pragma: \r\n"
- "Location: http://www.bonjourmadame.fr/\r\n"
- "Vary: Accept-Encoding\r\n"
- "Content-Length: 0\r\n"
- "Content-Type: text/html; charset=UTF-8\r\n"
- "Connection: keep-alive\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.status_code= 301
- ,.response_status= "Moved Permanently"
- ,.num_headers= 9
- ,.headers=
- { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
- , { "Server", "Apache/2.2.3 (Red Hat)" }
- , { "Cache-Control", "public" }
- , { "Pragma", "" }
- , { "Location", "http://www.bonjourmadame.fr/" }
- , { "Vary", "Accept-Encoding" }
- , { "Content-Length", "0" }
- , { "Content-Type", "text/html; charset=UTF-8" }
- , { "Connection", "keep-alive" }
- }
- ,.body= ""
- }
- #define RES_FIELD_UNDERSCORE 9
- , {.name= "field underscore"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n"
- "Server: Apache\r\n"
- "Cache-Control: no-cache, must-revalidate\r\n"
- "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
- ".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n"
- "Vary: Accept-Encoding\r\n"
- "_eep-Alive: timeout=45\r\n"
- "_onnection: Keep-Alive\r\n"
- "Transfer-Encoding: chunked\r\n"
- "Content-Type: text/html\r\n"
- "Connection: close\r\n"
- "\r\n"
- "0\r\n\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 11
- ,.headers=
- { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
- , { "Server", "Apache" }
- , { "Cache-Control", "no-cache, must-revalidate" }
- , { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" }
- , { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" }
- , { "Vary", "Accept-Encoding" }
- , { "_eep-Alive", "timeout=45" }
- , { "_onnection", "Keep-Alive" }
- , { "Transfer-Encoding", "chunked" }
- , { "Content-Type", "text/html" }
- , { "Connection", "close" }
- }
- ,.body= ""
- ,.num_chunks_complete= 1
- ,.chunk_lengths= {}
- }
- #define NON_ASCII_IN_STATUS_LINE 10
- , {.name= "non-ASCII in status line"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n"
- "Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n"
- "Content-Length: 0\r\n"
- "Connection: close\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 500
- ,.response_status= "Oriëntatieprobleem"
- ,.num_headers= 3
- ,.headers=
- { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
- , { "Content-Length", "0" }
- , { "Connection", "close" }
- }
- ,.body= ""
- }
- #define HTTP_VERSION_0_9 11
- , {.name= "http version 0.9"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/0.9 200 OK\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 0
- ,.http_minor= 9
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 0
- ,.headers=
- {}
- ,.body= ""
- }
- #define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12
- , {.name= "neither content-length nor transfer-encoding response"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/plain\r\n"
- "\r\n"
- "hello world"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 1
- ,.headers=
- { { "Content-Type", "text/plain" }
- }
- ,.body= "hello world"
- }
- #define NO_BODY_HTTP10_KA_200 13
- , {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.0 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 1
- ,.http_minor= 0
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 1
- ,.headers=
- { { "Connection", "keep-alive" }
- }
- ,.body_size= 0
- ,.body= ""
- }
- #define NO_BODY_HTTP10_KA_204 14
- , {.name= "HTTP/1.0 with keep-alive and a 204 status"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.0 204 No content\r\n"
- "Connection: keep-alive\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.status_code= 204
- ,.response_status= "No content"
- ,.num_headers= 1
- ,.headers=
- { { "Connection", "keep-alive" }
- }
- ,.body_size= 0
- ,.body= ""
- }
- #define NO_BODY_HTTP11_KA_200 15
- , {.name= "HTTP/1.1 with an EOF-terminated 200 status"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 0
- ,.headers={}
- ,.body_size= 0
- ,.body= ""
- }
- #define NO_BODY_HTTP11_KA_204 16
- , {.name= "HTTP/1.1 with a 204 status"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 204 No content\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 204
- ,.response_status= "No content"
- ,.num_headers= 0
- ,.headers={}
- ,.body_size= 0
- ,.body= ""
- }
- #define NO_BODY_HTTP11_NOKA_204 17
- , {.name= "HTTP/1.1 with a 204 status and keep-alive disabled"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 204 No content\r\n"
- "Connection: close\r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 204
- ,.response_status= "No content"
- ,.num_headers= 1
- ,.headers=
- { { "Connection", "close" }
- }
- ,.body_size= 0
- ,.body= ""
- }
- #define NO_BODY_HTTP11_KA_CHUNKED_200 18
- , {.name= "HTTP/1.1 with chunked endocing and a 200 response"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "Transfer-Encoding: chunked\r\n"
- "\r\n"
- "0\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 1
- ,.headers=
- { { "Transfer-Encoding", "chunked" }
- }
- ,.body_size= 0
- ,.body= ""
- ,.num_chunks_complete= 1
- }
- #if !HTTP_PARSER_STRICT
- #define SPACE_IN_FIELD_RES 19
- , {.name= "field space"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 OK\r\n"
- "Server: Microsoft-IIS/6.0\r\n"
- "X-Powered-By: ASP.NET\r\n"
- "en-US Content-Type: text/xml\r\n"
- "Content-Type: text/xml\r\n"
- "Content-Length: 16\r\n"
- "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
- "Connection: keep-alive\r\n"
- "\r\n"
- "<xml>hello</xml>"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 7
- ,.headers=
- { { "Server", "Microsoft-IIS/6.0" }
- , { "X-Powered-By", "ASP.NET" }
- , { "en-US Content-Type", "text/xml" }
- , { "Content-Type", "text/xml" }
- , { "Content-Length", "16" }
- , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
- , { "Connection", "keep-alive" }
- }
- ,.body= "<xml>hello</xml>"
- }
- #endif
- #define AMAZON_COM 20
- , {.name= "amazon.com"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 301 MovedPermanently\r\n"
- "Date: Wed, 15 May 2013 17:06:33 GMT\r\n"
- "Server: Server\r\n"
- "x-amz-id-1: 0GPHKXSJQ826RK7GZEB2\r\n"
- "p3p: policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"\r\n"
- "x-amz-id-2: STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD\r\n"
- "Location: http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846\r\n"
- "Vary: Accept-Encoding,User-Agent\r\n"
- "Content-Type: text/html; charset=ISO-8859-1\r\n"
- "Transfer-Encoding: chunked\r\n"
- "\r\n"
- "1\r\n"
- "\n\r\n"
- "0\r\n"
- "\r\n"
- ,.should_keep_alive= TRUE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 301
- ,.response_status= "MovedPermanently"
- ,.num_headers= 9
- ,.headers= { { "Date", "Wed, 15 May 2013 17:06:33 GMT" }
- , { "Server", "Server" }
- , { "x-amz-id-1", "0GPHKXSJQ826RK7GZEB2" }
- , { "p3p", "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" }
- , { "x-amz-id-2", "STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD" }
- , { "Location", "http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846" }
- , { "Vary", "Accept-Encoding,User-Agent" }
- , { "Content-Type", "text/html; charset=ISO-8859-1" }
- , { "Transfer-Encoding", "chunked" }
- }
- ,.body= "\n"
- ,.num_chunks_complete= 2
- ,.chunk_lengths= { 1 }
- }
- #define EMPTY_REASON_PHRASE_AFTER_SPACE 20
- , {.name= "empty reason phrase after space"
- ,.type= HTTP_RESPONSE
- ,.raw= "HTTP/1.1 200 \r\n"
- "\r\n"
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= TRUE
- ,.http_major= 1
- ,.http_minor= 1
- ,.status_code= 200
- ,.response_status= ""
- ,.num_headers= 0
- ,.headers= {}
- ,.body= ""
- }
- , {.name= NULL }
- };
- size_t
- strnlen(const char *s, size_t maxlen)
- {
- const char *p;
- p = memchr(s, '\0', maxlen);
- if (p == NULL)
- return maxlen;
- return p - s;
- }
- size_t
- strlncat(char *dst, size_t len, const char *src, size_t n)
- {
- size_t slen;
- size_t dlen;
- size_t rlen;
- size_t ncpy;
- slen = strnlen(src, n);
- dlen = strnlen(dst, len);
- if (dlen < len) {
- rlen = len - dlen;
- ncpy = slen < rlen ? slen : (rlen - 1);
- memcpy(dst + dlen, src, ncpy);
- dst[dlen + ncpy] = '\0';
- }
- assert(len > slen + dlen);
- return slen + dlen;
- }
- size_t
- strlcat(char *dst, const char *src, size_t len)
- {
- return strlncat(dst, len, src, (size_t) -1);
- }
- size_t
- strlncpy(char *dst, size_t len, const char *src, size_t n)
- {
- size_t slen;
- size_t ncpy;
- slen = strnlen(src, n);
- if (len > 0) {
- ncpy = slen < len ? slen : (len - 1);
- memcpy(dst, src, ncpy);
- dst[ncpy] = '\0';
- }
- assert(len > slen);
- return slen;
- }
- size_t
- strlcpy(char *dst, const char *src, size_t len)
- {
- return strlncpy(dst, len, src, (size_t) -1);
- }
- int
- request_url_cb (http_parser *p, const char *buf, size_t len)
- {
- assert(p == parser);
- strlncat(messages[num_messages].request_url,
- sizeof(messages[num_messages].request_url),
- buf,
- len);
- return 0;
- }
- int
- header_field_cb (http_parser *p, const char *buf, size_t len)
- {
- assert(p == parser);
- struct message *m = &messages[num_messages];
- if (m->last_header_element != FIELD)
- m->num_headers++;
- strlncat(m->headers[m->num_headers-1][0],
- sizeof(m->headers[m->num_headers-1][0]),
- buf,
- len);
- m->last_header_element = FIELD;
- return 0;
- }
- int
- header_value_cb (http_parser *p, const char *buf, size_t len)
- {
- assert(p == parser);
- struct message *m = &messages[num_messages];
- strlncat(m->headers[m->num_headers-1][1],
- sizeof(m->headers[m->num_headers-1][1]),
- buf,
- len);
- m->last_header_element = VALUE;
- return 0;
- }
- void
- check_body_is_final (const http_parser *p)
- {
- if (messages[num_messages].body_is_final) {
- fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
- "on last on_body callback call "
- "but it doesn't! ***\n\n");
- assert(0);
- abort();
- }
- messages[num_messages].body_is_final = http_body_is_final(p);
- }
- int
- body_cb (http_parser *p, const char *buf, size_t len)
- {
- assert(p == parser);
- strlncat(messages[num_messages].body,
- sizeof(messages[num_messages].body),
- buf,
- len);
- messages[num_messages].body_size += len;
- check_body_is_final(p);
-
- return 0;
- }
- int
- count_body_cb (http_parser *p, const char *buf, size_t len)
- {
- assert(p == parser);
- assert(buf);
- messages[num_messages].body_size += len;
- check_body_is_final(p);
- return 0;
- }
- int
- message_begin_cb (http_parser *p)
- {
- assert(p == parser);
- messages[num_messages].message_begin_cb_called = TRUE;
- return 0;
- }
- int
- headers_complete_cb (http_parser *p)
- {
- assert(p == parser);
- messages[num_messages].method = parser->method;
- messages[num_messages].status_code = parser->status_code;
- messages[num_messages].http_major = parser->http_major;
- messages[num_messages].http_minor = parser->http_minor;
- messages[num_messages].headers_complete_cb_called = TRUE;
- messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
- return 0;
- }
- int
- message_complete_cb (http_parser *p)
- {
- assert(p == parser);
- if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser))
- {
- fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same "
- "value in both on_message_complete and on_headers_complete "
- "but it doesn't! ***\n\n");
- assert(0);
- abort();
- }
- if (messages[num_messages].body_size &&
- http_body_is_final(p) &&
- !messages[num_messages].body_is_final)
- {
- fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
- "on last on_body callback call "
- "but it doesn't! ***\n\n");
- assert(0);
- abort();
- }
- messages[num_messages].message_complete_cb_called = TRUE;
- messages[num_messages].message_complete_on_eof = currently_parsing_eof;
- num_messages++;
- return 0;
- }
- int
- response_status_cb (http_parser *p, const char *buf, size_t len)
- {
- assert(p == parser);
- strlncat(messages[num_messages].response_status,
- sizeof(messages[num_messages].response_status),
- buf,
- len);
- return 0;
- }
- int
- chunk_header_cb (http_parser *p)
- {
- assert(p == parser);
- int chunk_idx = messages[num_messages].num_chunks;
- messages[num_messages].num_chunks++;
- if (chunk_idx < MAX_CHUNKS) {
- messages[num_messages].chunk_lengths[chunk_idx] = p->content_length;
- }
- return 0;
- }
- int
- chunk_complete_cb (http_parser *p)
- {
- assert(p == parser);
-
- assert(messages[num_messages].num_chunks ==
- messages[num_messages].num_chunks_complete + 1);
- messages[num_messages].num_chunks_complete++;
- return 0;
- }
- int
- dontcall_message_begin_cb (http_parser *p)
- {
- if (p) { }
- fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
- abort();
- }
- int
- dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
- {
- if (p || buf || len) { }
- fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
- abort();
- }
- int
- dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
- {
- if (p || buf || len) { }
- fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
- abort();
- }
- int
- dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
- {
- if (p || buf || len) { }
- fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
- abort();
- }
- int
- dontcall_body_cb (http_parser *p, const char *buf, size_t len)
- {
- if (p || buf || len) { }
- fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
- abort();
- }
- int
- dontcall_headers_complete_cb (http_parser *p)
- {
- if (p) { }
- fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
- "parser ***\n\n");
- abort();
- }
- int
- dontcall_message_complete_cb (http_parser *p)
- {
- if (p) { }
- fprintf(stderr, "\n\n*** on_message_complete() called on paused "
- "parser ***\n\n");
- abort();
- }
- int
- dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
- {
- if (p || buf || len) { }
- fprintf(stderr, "\n\n*** on_status() called on paused parser ***\n\n");
- abort();
- }
- int
- dontcall_chunk_header_cb (http_parser *p)
- {
- if (p) { }
- fprintf(stderr, "\n\n*** on_chunk_header() called on paused parser ***\n\n");
- exit(1);
- }
- int
- dontcall_chunk_complete_cb (http_parser *p)
- {
- if (p) { }
- fprintf(stderr, "\n\n*** on_chunk_complete() "
- "called on paused parser ***\n\n");
- exit(1);
- }
- static http_parser_settings settings_dontcall =
- {.on_message_begin = dontcall_message_begin_cb
- ,.on_header_field = dontcall_header_field_cb
- ,.on_header_value = dontcall_header_value_cb
- ,.on_url = dontcall_request_url_cb
- ,.on_status = dontcall_response_status_cb
- ,.on_body = dontcall_body_cb
- ,.on_headers_complete = dontcall_headers_complete_cb
- ,.on_message_complete = dontcall_message_complete_cb
- ,.on_chunk_header = dontcall_chunk_header_cb
- ,.on_chunk_complete = dontcall_chunk_complete_cb
- };
- int
- pause_message_begin_cb (http_parser *p)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return message_begin_cb(p);
- }
- int
- pause_header_field_cb (http_parser *p, const char *buf, size_t len)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return header_field_cb(p, buf, len);
- }
- int
- pause_header_value_cb (http_parser *p, const char *buf, size_t len)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return header_value_cb(p, buf, len);
- }
- int
- pause_request_url_cb (http_parser *p, const char *buf, size_t len)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return request_url_cb(p, buf, len);
- }
- int
- pause_body_cb (http_parser *p, const char *buf, size_t len)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return body_cb(p, buf, len);
- }
- int
- pause_headers_complete_cb (http_parser *p)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return headers_complete_cb(p);
- }
- int
- pause_message_complete_cb (http_parser *p)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return message_complete_cb(p);
- }
- int
- pause_response_status_cb (http_parser *p, const char *buf, size_t len)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return response_status_cb(p, buf, len);
- }
- int
- pause_chunk_header_cb (http_parser *p)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return chunk_header_cb(p);
- }
- int
- pause_chunk_complete_cb (http_parser *p)
- {
- http_parser_pause(p, 1);
- *current_pause_parser = settings_dontcall;
- return chunk_complete_cb(p);
- }
- static http_parser_settings settings_pause =
- {.on_message_begin = pause_message_begin_cb
- ,.on_header_field = pause_header_field_cb
- ,.on_header_value = pause_header_value_cb
- ,.on_url = pause_request_url_cb
- ,.on_status = pause_response_status_cb
- ,.on_body = pause_body_cb
- ,.on_headers_complete = pause_headers_complete_cb
- ,.on_message_complete = pause_message_complete_cb
- ,.on_chunk_header = pause_chunk_header_cb
- ,.on_chunk_complete = pause_chunk_complete_cb
- };
- static http_parser_settings settings =
- {.on_message_begin = message_begin_cb
- ,.on_header_field = header_field_cb
- ,.on_header_value = header_value_cb
- ,.on_url = request_url_cb
- ,.on_status = response_status_cb
- ,.on_body = body_cb
- ,.on_headers_complete = headers_complete_cb
- ,.on_message_complete = message_complete_cb
- ,.on_chunk_header = chunk_header_cb
- ,.on_chunk_complete = chunk_complete_cb
- };
- static http_parser_settings settings_count_body =
- {.on_message_begin = message_begin_cb
- ,.on_header_field = header_field_cb
- ,.on_header_value = header_value_cb
- ,.on_url = request_url_cb
- ,.on_status = response_status_cb
- ,.on_body = count_body_cb
- ,.on_headers_complete = headers_complete_cb
- ,.on_message_complete = message_complete_cb
- ,.on_chunk_header = chunk_header_cb
- ,.on_chunk_complete = chunk_complete_cb
- };
- static http_parser_settings settings_null =
- {.on_message_begin = 0
- ,.on_header_field = 0
- ,.on_header_value = 0
- ,.on_url = 0
- ,.on_status = 0
- ,.on_body = 0
- ,.on_headers_complete = 0
- ,.on_message_complete = 0
- ,.on_chunk_header = 0
- ,.on_chunk_complete = 0
- };
- void
- parser_init (enum http_parser_type type)
- {
- num_messages = 0;
- assert(parser == NULL);
- parser = malloc(sizeof(http_parser));
- http_parser_init(parser, type);
- memset(&messages, 0, sizeof messages);
- }
- void
- parser_free ()
- {
- assert(parser);
- free(parser);
- parser = NULL;
- }
- size_t parse (const char *buf, size_t len)
- {
- size_t nparsed;
- currently_parsing_eof = (len == 0);
- nparsed = http_parser_execute(parser, &settings, buf, len);
- return nparsed;
- }
- size_t parse_count_body (const char *buf, size_t len)
- {
- size_t nparsed;
- currently_parsing_eof = (len == 0);
- nparsed = http_parser_execute(parser, &settings_count_body, buf, len);
- return nparsed;
- }
- size_t parse_pause (const char *buf, size_t len)
- {
- size_t nparsed;
- http_parser_settings s = settings_pause;
- currently_parsing_eof = (len == 0);
- current_pause_parser = &s;
- nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
- return nparsed;
- }
- static inline int
- check_str_eq (const struct message *m,
- const char *prop,
- const char *expected,
- const char *found) {
- if ((expected == NULL) != (found == NULL)) {
- printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
- printf("expected %s\n", (expected == NULL) ? "NULL" : expected);
- printf(" found %s\n", (found == NULL) ? "NULL" : found);
- return 0;
- }
- if (expected != NULL && 0 != strcmp(expected, found)) {
- printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
- printf("expected '%s'\n", expected);
- printf(" found '%s'\n", found);
- return 0;
- }
- return 1;
- }
- static inline int
- check_num_eq (const struct message *m,
- const char *prop,
- int expected,
- int found) {
- if (expected != found) {
- printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
- printf("expected %d\n", expected);
- printf(" found %d\n", found);
- return 0;
- }
- return 1;
- }
- #define MESSAGE_CHECK_STR_EQ(expected, found, prop) \
- if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0
- #define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
- if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
- #define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \
- do { \
- char ubuf[256]; \
- \
- if ((u)->field_set & (1 << (fn))) { \
- memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \
- (u)->field_data[(fn)].len); \
- ubuf[(u)->field_data[(fn)].len] = '\0'; \
- } else { \
- ubuf[0] = '\0'; \
- } \
- \
- check_str_eq(expected, #prop, expected->prop, ubuf); \
- } while(0)
- int
- message_eq (int index, const struct message *expected)
- {
- int i;
- struct message *m = &messages[index];
- MESSAGE_CHECK_NUM_EQ(expected, m, http_major);
- MESSAGE_CHECK_NUM_EQ(expected, m, http_minor);
- if (expected->type == HTTP_REQUEST) {
- MESSAGE_CHECK_NUM_EQ(expected, m, method);
- } else {
- MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
- MESSAGE_CHECK_STR_EQ(expected, m, response_status);
- }
- MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
- MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
- assert(m->message_begin_cb_called);
- assert(m->headers_complete_cb_called);
- assert(m->message_complete_cb_called);
- MESSAGE_CHECK_STR_EQ(expected, m, request_url);
-
- if (*m->request_url && m->method != HTTP_CONNECT) {
- struct http_parser_url u;
- if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
- fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
- m->request_url);
- abort();
- }
- if (expected->host) {
- MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST);
- }
- if (expected->userinfo) {
- MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO);
- }
- m->port = (u.field_set & (1 << UF_PORT)) ?
- u.port : 0;
- MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY);
- MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT);
- MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH);
- MESSAGE_CHECK_NUM_EQ(expected, m, port);
- }
- if (expected->body_size) {
- MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
- } else {
- MESSAGE_CHECK_STR_EQ(expected, m, body);
- }
- assert(m->num_chunks == m->num_chunks_complete);
- MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete);
- for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) {
- MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]);
- }
- MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
- int r;
- for (i = 0; i < m->num_headers; i++) {
- r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]);
- if (!r) return 0;
- r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]);
- if (!r) return 0;
- }
- MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
- return 1;
- }
- size_t
- count_parsed_messages(const size_t nmsgs, ...) {
- size_t i;
- va_list ap;
- va_start(ap, nmsgs);
- for (i = 0; i < nmsgs; i++) {
- struct message *m = va_arg(ap, struct message *);
- if (m->upgrade) {
- va_end(ap);
- return i + 1;
- }
- }
- va_end(ap);
- return nmsgs;
- }
- void
- upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
- va_list ap;
- size_t i;
- size_t off = 0;
- va_start(ap, nmsgs);
- for (i = 0; i < nmsgs; i++) {
- struct message *m = va_arg(ap, struct message *);
- off += strlen(m->raw);
- if (m->upgrade) {
- off -= strlen(m->upgrade);
-
- if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
- abort();
- }
-
- *(body + nread + strlen(m->upgrade)) = '\0';
- messages[num_messages -1 ].upgrade = body + nread;
- va_end(ap);
- return;
- }
- }
- va_end(ap);
- printf("\n\n*** Error: expected a message with upgrade ***\n");
- abort();
- }
- static void
- print_error (const char *raw, size_t error_location)
- {
- fprintf(stderr, "\n*** %s ***\n\n",
- http_errno_description(HTTP_PARSER_ERRNO(parser)));
- int this_line = 0, char_len = 0;
- size_t i, j, len = strlen(raw), error_location_line = 0;
- for (i = 0; i < len; i++) {
- if (i == error_location) this_line = 1;
- switch (raw[i]) {
- case '\r':
- char_len = 2;
- fprintf(stderr, "\\r");
- break;
- case '\n':
- fprintf(stderr, "\\n\n");
- if (this_line) goto print;
- error_location_line = 0;
- continue;
- default:
- char_len = 1;
- fputc(raw[i], stderr);
- break;
- }
- if (!this_line) error_location_line += char_len;
- }
- fprintf(stderr, "[eof]\n");
- print:
- for (j = 0; j < error_location_line; j++) {
- fputc(' ', stderr);
- }
- fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
- }
- void
- test_preserve_data (void)
- {
- char my_data[] = "application-specific data";
- http_parser parser;
- parser.data = my_data;
- http_parser_init(&parser, HTTP_REQUEST);
- if (parser.data != my_data) {
- printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
- abort();
- }
- }
- struct url_test {
- const char *name;
- const char *url;
- int is_connect;
- struct http_parser_url u;
- int rv;
- };
- const struct url_test url_tests[] =
- { {.name="proxy request"
- ,.url="http://hostname/"
- ,.is_connect=0
- ,.u=
- {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 7, 8 }
- ,{ 0, 0 }
- ,{ 15, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="proxy request with port"
- ,.url="http://hostname:444/"
- ,.is_connect=0
- ,.u=
- {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
- ,.port=444
- ,.field_data=
- {{ 0, 4 }
- ,{ 7, 8 }
- ,{ 16, 3 }
- ,{ 19, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="CONNECT request"
- ,.url="hostname:443"
- ,.is_connect=1
- ,.u=
- {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
- ,.port=443
- ,.field_data=
- {{ 0, 0 }
- ,{ 0, 8 }
- ,{ 9, 3 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="CONNECT request but not connect"
- ,.url="hostname:443"
- ,.is_connect=0
- ,.rv=1
- }
- , {.name="proxy ipv6 request"
- ,.url="http://[1:2::3:4]/"
- ,.is_connect=0
- ,.u=
- {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 8, 8 }
- ,{ 0, 0 }
- ,{ 17, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="proxy ipv6 request with port"
- ,.url="http://[1:2::3:4]:67/"
- ,.is_connect=0
- ,.u=
- {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
- ,.port=67
- ,.field_data=
- {{ 0, 4 }
- ,{ 8, 8 }
- ,{ 18, 2 }
- ,{ 20, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="CONNECT ipv6 address"
- ,.url="[1:2::3:4]:443"
- ,.is_connect=1
- ,.u=
- {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
- ,.port=443
- ,.field_data=
- {{ 0, 0 }
- ,{ 1, 8 }
- ,{ 11, 3 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="ipv4 in ipv6 address"
- ,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/"
- ,.is_connect=0
- ,.u=
- {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 8, 37 }
- ,{ 0, 0 }
- ,{ 46, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="extra ? in query string"
- ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,"
- "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,"
- "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
- ,.is_connect=0
- ,.u=
- {.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 7, 10 }
- ,{ 0, 0 }
- ,{ 17, 12 }
- ,{ 30,187 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="space URL encoded"
- ,.url="/toto.html?toto=a%20b"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_PATH) | (1<<UF_QUERY)
- ,.port=0
- ,.field_data=
- {{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 10 }
- ,{ 11, 10 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="URL fragment"
- ,.url="/toto.html#titi"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_PATH) | (1<<UF_FRAGMENT)
- ,.port=0
- ,.field_data=
- {{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 10 }
- ,{ 0, 0 }
- ,{ 11, 4 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="complex URL fragment"
- ,.url="http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
- "http://www.example.com/index.html?foo=bar&hello=world#midpage"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY) |\
- (1<<UF_FRAGMENT)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 7, 22 }
- ,{ 0, 0 }
- ,{ 29, 6 }
- ,{ 36, 69 }
- ,{106, 7 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="complex URL from node js url parser doc"
- ,.url="http://host.com:8080/p/a/t/h?query=string#hash"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
- (1<<UF_QUERY) | (1<<UF_FRAGMENT)
- ,.port=8080
- ,.field_data=
- {{ 0, 4 }
- ,{ 7, 8 }
- ,{ 16, 4 }
- ,{ 20, 8 }
- ,{ 29, 12 }
- ,{ 42, 4 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="complex URL with basic auth from node js url parser doc"
- ,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
- (1<<UF_QUERY) | (1<<UF_FRAGMENT) | (1<<UF_USERINFO)
- ,.port=8080
- ,.field_data=
- {{ 0, 4 }
- ,{ 11, 8 }
- ,{ 20, 4 }
- ,{ 24, 8 }
- ,{ 33, 12 }
- ,{ 46, 4 }
- ,{ 7, 3 }
- }
- }
- ,.rv=0
- }
- , {.name="double @"
- ,.url="http://a:b@@hostname:443/"
- ,.is_connect=0
- ,.rv=1
- }
- , {.name="proxy empty host"
- ,.url="http://:443/"
- ,.is_connect=0
- ,.rv=1
- }
- , {.name="proxy empty port"
- ,.url="http://hostname:/"
- ,.is_connect=0
- ,.rv=1
- }
- , {.name="CONNECT with basic auth"
- ,.url="a:b@hostname:443"
- ,.is_connect=1
- ,.rv=1
- }
- , {.name="CONNECT empty host"
- ,.url=":443"
- ,.is_connect=1
- ,.rv=1
- }
- , {.name="CONNECT empty port"
- ,.url="hostname:"
- ,.is_connect=1
- ,.rv=1
- }
- , {.name="CONNECT with extra bits"
- ,.url="hostname:443/"
- ,.is_connect=1
- ,.rv=1
- }
- , {.name="space in URL"
- ,.url="/foo bar/"
- ,.rv=1
- }
- , {.name="proxy basic auth with space url encoded"
- ,.url="http://a%20:b@host.com/"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 14, 8 }
- ,{ 0, 0 }
- ,{ 22, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 7, 6 }
- }
- }
- ,.rv=0
- }
- , {.name="carriage return in URL"
- ,.url="/foo\rbar/"
- ,.rv=1
- }
- , {.name="proxy double : in URL"
- ,.url="http://hostname::443/"
- ,.rv=1
- }
- , {.name="proxy basic auth with double :"
- ,.url="http://a::b@host.com/"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 12, 8 }
- ,{ 0, 0 }
- ,{ 20, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 7, 4 }
- }
- }
- ,.rv=0
- }
- , {.name="line feed in URL"
- ,.url="/foo\nbar/"
- ,.rv=1
- }
- , {.name="proxy empty basic auth"
- ,.url="http://@hostname/fo"
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 8, 8 }
- ,{ 0, 0 }
- ,{ 16, 3 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="proxy line feed in hostname"
- ,.url="http://host\name/fo"
- ,.rv=1
- }
- , {.name="proxy % in hostname"
- ,.url="http://host%name/fo"
- ,.rv=1
- }
- , {.name="proxy ; in hostname"
- ,.url="http://host;ame/fo"
- ,.rv=1
- }
- , {.name="proxy basic auth with unreservedchars"
- ,.url="http://a!;-_!=+$@host.com/"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 17, 8 }
- ,{ 0, 0 }
- ,{ 25, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 7, 9 }
- }
- }
- ,.rv=0
- }
- , {.name="proxy only empty basic auth"
- ,.url="http://@/fo"
- ,.rv=1
- }
- , {.name="proxy only basic auth"
- ,.url="http://toto@/fo"
- ,.rv=1
- }
- , {.name="proxy emtpy hostname"
- ,.url="http:///fo"
- ,.rv=1
- }
- , {.name="proxy = in URL"
- ,.url="http://host=ame/fo"
- ,.rv=1
- }
- , {.name="ipv6 address with Zone ID"
- ,.url="http://[fe80::a%25eth0]/"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 8, 14 }
- ,{ 0, 0 }
- ,{ 23, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="ipv6 address with Zone ID, but '%' is not percent-encoded"
- ,.url="http://[fe80::a%eth0]/"
- ,.is_connect=0
- ,.u=
- {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
- ,.port=0
- ,.field_data=
- {{ 0, 4 }
- ,{ 8, 12 }
- ,{ 0, 0 }
- ,{ 21, 1 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="ipv6 address ending with '%'"
- ,.url="http://[fe80::a%]/"
- ,.rv=1
- }
- , {.name="ipv6 address with Zone ID including bad character"
- ,.url="http://[fe80::a%$HOME]/"
- ,.rv=1
- }
- , {.name="just ipv6 Zone ID"
- ,.url="http://[%eth0]/"
- ,.rv=1
- }
- #if HTTP_PARSER_STRICT
- , {.name="tab in URL"
- ,.url="/foo\tbar/"
- ,.rv=1
- }
- , {.name="form feed in URL"
- ,.url="/foo\fbar/"
- ,.rv=1
- }
- #else
- , {.name="tab in URL"
- ,.url="/foo\tbar/"
- ,.u=
- {.field_set=(1 << UF_PATH)
- ,.field_data=
- {{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 9 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- , {.name="form feed in URL"
- ,.url="/foo\fbar/"
- ,.u=
- {.field_set=(1 << UF_PATH)
- ,.field_data=
- {{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 9 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- ,{ 0, 0 }
- }
- }
- ,.rv=0
- }
- #endif
- };
- void
- dump_url (const char *url, const struct http_parser_url *u)
- {
- unsigned int i;
- printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
- for (i = 0; i < UF_MAX; i++) {
- if ((u->field_set & (1 << i)) == 0) {
- printf("\tfield_data[%u]: unset\n", i);
- continue;
- }
- printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"",
- i,
- u->field_data[i].off,
- u->field_data[i].len,
- u->field_data[i].len,
- url + u->field_data[i].off);
- }
- }
- void
- test_parse_url (void)
- {
- struct http_parser_url u;
- const struct url_test *test;
- unsigned int i;
- int rv;
- for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) {
- test = &url_tests[i];
- memset(&u, 0, sizeof(u));
- rv = http_parser_parse_url(test->url,
- strlen(test->url),
- test->is_connect,
- &u);
- if (test->rv == 0) {
- if (rv != 0) {
- printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
- "unexpected rv %d ***\n\n", test->url, test->name, rv);
- abort();
- }
- if (memcmp(&u, &test->u, sizeof(u)) != 0) {
- printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n",
- test->url, test->name);
- printf("target http_parser_url:\n");
- dump_url(test->url, &test->u);
- printf("result http_parser_url:\n");
- dump_url(test->url, &u);
- abort();
- }
- } else {
-
- if (rv == 0) {
- printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
- "unexpected rv %d ***\n\n", test->url, test->name, rv);
- abort();
- }
- }
- }
- }
- void
- test_method_str (void)
- {
- assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
- assert(0 == strcmp("<unknown>", http_method_str(1337)));
- }
- void
- test_message (const struct message *message)
- {
- size_t raw_len = strlen(message->raw);
- size_t msg1len;
- for (msg1len = 0; msg1len < raw_len; msg1len++) {
- parser_init(message->type);
- size_t read;
- const char *msg1 = message->raw;
- const char *msg2 = msg1 + msg1len;
- size_t msg2len = raw_len - msg1len;
- if (msg1len) {
- read = parse(msg1, msg1len);
- if (message->upgrade && parser->upgrade && num_messages > 0) {
- messages[num_messages - 1].upgrade = msg1 + read;
- goto test;
- }
- if (read != msg1len) {
- print_error(msg1, read);
- abort();
- }
- }
- read = parse(msg2, msg2len);
- if (message->upgrade && parser->upgrade) {
- messages[num_messages - 1].upgrade = msg2 + read;
- goto test;
- }
- if (read != msg2len) {
- print_error(msg2, read);
- abort();
- }
- read = parse(NULL, 0);
- if (read != 0) {
- print_error(message->raw, read);
- abort();
- }
- test:
- if (num_messages != 1) {
- printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
- abort();
- }
- if(!message_eq(0, message)) abort();
- parser_free();
- }
- }
- void
- test_message_count_body (const struct message *message)
- {
- parser_init(message->type);
- size_t read;
- size_t l = strlen(message->raw);
- size_t i, toread;
- size_t chunk = 4024;
- for (i = 0; i < l; i+= chunk) {
- toread = MIN(l-i, chunk);
- read = parse_count_body(message->raw + i, toread);
- if (read != toread) {
- print_error(message->raw, read);
- abort();
- }
- }
- read = parse_count_body(NULL, 0);
- if (read != 0) {
- print_error(message->raw, read);
- abort();
- }
- if (num_messages != 1) {
- printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
- abort();
- }
- if(!message_eq(0, message)) abort();
- parser_free();
- }
- void
- test_simple (const char *buf, enum http_errno err_expected)
- {
- parser_init(HTTP_REQUEST);
- enum http_errno err;
- parse(buf, strlen(buf));
- err = HTTP_PARSER_ERRNO(parser);
- parse(NULL, 0);
- parser_free();
-
- #if HTTP_PARSER_STRICT
- if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) {
- #else
- if (err_expected != err) {
- #endif
- fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
- http_errno_name(err_expected), http_errno_name(err), buf);
- abort();
- }
- }
- void
- test_invalid_header_content (int req, const char* str)
- {
- http_parser parser;
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
- size_t parsed;
- const char *buf;
- buf = req ?
- "GET / HTTP/1.1\r\n" :
- "HTTP/1.1 200 OK\r\n";
- parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
- assert(parsed == strlen(buf));
- buf = str;
- size_t buflen = strlen(buf);
- parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
- if (parsed != buflen) {
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
- return;
- }
- fprintf(stderr,
- "\n*** Error expected but none in invalid header content test ***\n");
- abort();
- }
- void
- test_invalid_header_field_content_error (int req)
- {
- test_invalid_header_content(req, "Foo: F\01ailure");
- test_invalid_header_content(req, "Foo: B\02ar");
- }
- void
- test_invalid_header_field (int req, const char* str)
- {
- http_parser parser;
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
- size_t parsed;
- const char *buf;
- buf = req ?
- "GET / HTTP/1.1\r\n" :
- "HTTP/1.1 200 OK\r\n";
- parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
- assert(parsed == strlen(buf));
- buf = str;
- size_t buflen = strlen(buf);
- parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
- if (parsed != buflen) {
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
- return;
- }
- fprintf(stderr,
- "\n*** Error expected but none in invalid header token test ***\n");
- abort();
- }
- void
- test_invalid_header_field_token_error (int req)
- {
- test_invalid_header_field(req, "Fo@: Failure");
- test_invalid_header_field(req, "Foo\01\test: Bar");
- }
- void
- test_double_content_length_error (int req)
- {
- http_parser parser;
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
- size_t parsed;
- const char *buf;
- buf = req ?
- "GET / HTTP/1.1\r\n" :
- "HTTP/1.1 200 OK\r\n";
- parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
- assert(parsed == strlen(buf));
- buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n";
- size_t buflen = strlen(buf);
- parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
- if (parsed != buflen) {
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
- return;
- }
- fprintf(stderr,
- "\n*** Error expected but none in double content-length test ***\n");
- abort();
- }
- void
- test_chunked_content_length_error (int req)
- {
- http_parser parser;
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
- size_t parsed;
- const char *buf;
- buf = req ?
- "GET / HTTP/1.1\r\n" :
- "HTTP/1.1 200 OK\r\n";
- parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
- assert(parsed == strlen(buf));
- buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
- size_t buflen = strlen(buf);
- parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
- if (parsed != buflen) {
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
- return;
- }
- fprintf(stderr,
- "\n*** Error expected but none in chunked content-length test ***\n");
- abort();
- }
- void
- test_header_cr_no_lf_error (int req)
- {
- http_parser parser;
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
- size_t parsed;
- const char *buf;
- buf = req ?
- "GET / HTTP/1.1\r\n" :
- "HTTP/1.1 200 OK\r\n";
- parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
- assert(parsed == strlen(buf));
- buf = "Foo: 1\rBar: 1\r\n\r\n";
- size_t buflen = strlen(buf);
- parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
- if (parsed != buflen) {
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_LF_EXPECTED);
- return;
- }
- fprintf(stderr,
- "\n*** Error expected but none in header whitespace test ***\n");
- abort();
- }
- void
- test_header_overflow_error (int req)
- {
- http_parser parser;
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
- size_t parsed;
- const char *buf;
- buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.0 200 OK\r\n";
- parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
- assert(parsed == strlen(buf));
- buf = "header-key: header-value\r\n";
- size_t buflen = strlen(buf);
- int i;
- for (i = 0; i < 10000; i++) {
- parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
- if (parsed != buflen) {
-
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
- return;
- }
- }
- fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
- abort();
- }
- void
- test_header_nread_value ()
- {
- http_parser parser;
- http_parser_init(&parser, HTTP_REQUEST);
- size_t parsed;
- const char *buf;
- buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n";
- parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
- assert(parsed == strlen(buf));
- assert(parser.nread == strlen(buf));
- }
- static void
- test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
- {
- http_parser parser;
- http_parser_init(&parser, HTTP_RESPONSE);
- http_parser_execute(&parser, &settings_null, buf, buflen);
- if (expect_ok)
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK);
- else
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH);
- }
- void
- test_header_content_length_overflow_error (void)
- {
- #define X(size) \
- "HTTP/1.1 200 OK\r\n" \
- "Content-Length: " #size "\r\n" \
- "\r\n"
- const char a[] = X(1844674407370955160);
- const char b[] = X(18446744073709551615);
- const char c[] = X(18446744073709551616);
- #undef X
- test_content_length_overflow(a, sizeof(a) - 1, 1);
- test_content_length_overflow(b, sizeof(b) - 1, 0);
- test_content_length_overflow(c, sizeof(c) - 1, 0);
- }
- void
- test_chunk_content_length_overflow_error (void)
- {
- #define X(size) \
- "HTTP/1.1 200 OK\r\n" \
- "Transfer-Encoding: chunked\r\n" \
- "\r\n" \
- #size "\r\n" \
- "..."
- const char a[] = X(FFFFFFFFFFFFFFE);
- const char b[] = X(FFFFFFFFFFFFFFFF);
- const char c[] = X(10000000000000000);
- #undef X
- test_content_length_overflow(a, sizeof(a) - 1, 1);
- test_content_length_overflow(b, sizeof(b) - 1, 0);
- test_content_length_overflow(c, sizeof(c) - 1, 0);
- }
- void
- test_no_overflow_long_body (int req, size_t length)
- {
- http_parser parser;
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
- size_t parsed;
- size_t i;
- char buf1[3000];
- size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n",
- req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length);
- parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
- if (parsed != buf1len)
- goto err;
- for (i = 0; i < length; i++) {
- char foo = 'a';
- parsed = http_parser_execute(&parser, &settings_null, &foo, 1);
- if (parsed != 1)
- goto err;
- }
- parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
- if (parsed != buf1len) goto err;
- return;
- err:
- fprintf(stderr,
- "\n*** error in test_no_overflow_long_body %s of length %lu ***\n",
- req ? "REQUEST" : "RESPONSE",
- (unsigned long)length);
- abort();
- }
- void
- test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
- {
- int message_count = count_parsed_messages(3, r1, r2, r3);
- char total[ strlen(r1->raw)
- + strlen(r2->raw)
- + strlen(r3->raw)
- + 1
- ];
- total[0] = '\0';
- strcat(total, r1->raw);
- strcat(total, r2->raw);
- strcat(total, r3->raw);
- parser_init(r1->type);
- size_t read;
- read = parse(total, strlen(total));
- if (parser->upgrade) {
- upgrade_message_fix(total, read, 3, r1, r2, r3);
- goto test;
- }
- if (read != strlen(total)) {
- print_error(total, read);
- abort();
- }
- read = parse(NULL, 0);
- if (read != 0) {
- print_error(total, read);
- abort();
- }
- test:
- if (message_count != num_messages) {
- fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
- abort();
- }
- if (!message_eq(0, r1)) abort();
- if (message_count > 1 && !message_eq(1, r2)) abort();
- if (message_count > 2 && !message_eq(2, r3)) abort();
- parser_free();
- }
- void
- test_scan (const struct message *r1, const struct message *r2, const struct message *r3)
- {
- char total[80*1024] = "\0";
- char buf1[80*1024] = "\0";
- char buf2[80*1024] = "\0";
- char buf3[80*1024] = "\0";
- strcat(total, r1->raw);
- strcat(total, r2->raw);
- strcat(total, r3->raw);
- size_t read;
- int total_len = strlen(total);
- int total_ops = 2 * (total_len - 1) * (total_len - 2) / 2;
- int ops = 0 ;
- size_t buf1_len, buf2_len, buf3_len;
- int message_count = count_parsed_messages(3, r1, r2, r3);
- int i,j,type_both;
- for (type_both = 0; type_both < 2; type_both ++ ) {
- for (j = 2; j < total_len; j ++ ) {
- for (i = 1; i < j; i ++ ) {
- if (ops % 1000 == 0) {
- printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops);
- fflush(stdout);
- }
- ops += 1;
- parser_init(type_both ? HTTP_BOTH : r1->type);
- buf1_len = i;
- strlncpy(buf1, sizeof(buf1), total, buf1_len);
- buf1[buf1_len] = 0;
- buf2_len = j - i;
- strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
- buf2[buf2_len] = 0;
- buf3_len = total_len - j;
- strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
- buf3[buf3_len] = 0;
- read = parse(buf1, buf1_len);
- if (parser->upgrade) goto test;
- if (read != buf1_len) {
- print_error(buf1, read);
- goto error;
- }
- read += parse(buf2, buf2_len);
- if (parser->upgrade) goto test;
- if (read != buf1_len + buf2_len) {
- print_error(buf2, read);
- goto error;
- }
- read += parse(buf3, buf3_len);
- if (parser->upgrade) goto test;
- if (read != buf1_len + buf2_len + buf3_len) {
- print_error(buf3, read);
- goto error;
- }
- parse(NULL, 0);
- test:
- if (parser->upgrade) {
- upgrade_message_fix(total, read, 3, r1, r2, r3);
- }
- if (message_count != num_messages) {
- fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
- message_count, num_messages);
- goto error;
- }
- if (!message_eq(0, r1)) {
- fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n");
- goto error;
- }
- if (message_count > 1 && !message_eq(1, r2)) {
- fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
- goto error;
- }
- if (message_count > 2 && !message_eq(2, r3)) {
- fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
- goto error;
- }
- parser_free();
- }
- }
- }
- puts("\b\b\b\b100%");
- return;
- error:
- fprintf(stderr, "i=%d j=%d\n", i, j);
- fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
- fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
- fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
- abort();
- }
- char *
- create_large_chunked_message (int body_size_in_kb, const char* headers)
- {
- int i;
- size_t wrote = 0;
- size_t headers_len = strlen(headers);
- size_t bufsize = headers_len + (5+1024+2)*body_size_in_kb + 6;
- char * buf = malloc(bufsize);
- memcpy(buf, headers, headers_len);
- wrote += headers_len;
- for (i = 0; i < body_size_in_kb; i++) {
-
- memcpy(buf + wrote, "400\r\n", 5);
- wrote += 5;
- memset(buf + wrote, 'C', 1024);
- wrote += 1024;
- strcpy(buf + wrote, "\r\n");
- wrote += 2;
- }
- memcpy(buf + wrote, "0\r\n\r\n", 6);
- wrote += 6;
- assert(wrote == bufsize);
- return buf;
- }
- void
- test_message_pause (const struct message *msg)
- {
- char *buf = (char*) msg->raw;
- size_t buflen = strlen(msg->raw);
- size_t nread;
- parser_init(msg->type);
- do {
- nread = parse_pause(buf, buflen);
-
-
- if (messages[0].message_complete_cb_called &&
- msg->upgrade &&
- parser->upgrade) {
- messages[0].upgrade = buf + nread;
- goto test;
- }
- if (nread < buflen) {
-
- if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
- parser_free();
- return;
- }
- assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
- }
- buf += nread;
- buflen -= nread;
- http_parser_pause(parser, 0);
- } while (buflen > 0);
- nread = parse_pause(NULL, 0);
- assert (nread == 0);
- test:
- if (num_messages != 1) {
- printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
- abort();
- }
- if(!message_eq(0, msg)) abort();
- parser_free();
- }
- int
- main (void)
- {
- parser = NULL;
- int i, j, k;
- int request_count;
- int response_count;
- unsigned long version;
- unsigned major;
- unsigned minor;
- unsigned patch;
- version = http_parser_version();
- major = (version >> 16) & 255;
- minor = (version >> 8) & 255;
- patch = version & 255;
- printf("http_parser v%u.%u.%u (0x%06lx)\n", major, minor, patch, version);
- printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
- for (request_count = 0; requests[request_count].name; request_count++);
- for (response_count = 0; responses[response_count].name; response_count++);
-
- test_preserve_data();
- test_parse_url();
- test_method_str();
-
- test_header_nread_value();
-
- test_header_overflow_error(HTTP_REQUEST);
- test_no_overflow_long_body(HTTP_REQUEST, 1000);
- test_no_overflow_long_body(HTTP_REQUEST, 100000);
- test_header_overflow_error(HTTP_RESPONSE);
- test_no_overflow_long_body(HTTP_RESPONSE, 1000);
- test_no_overflow_long_body(HTTP_RESPONSE, 100000);
- test_header_content_length_overflow_error();
- test_chunk_content_length_overflow_error();
-
- test_double_content_length_error(HTTP_REQUEST);
- test_chunked_content_length_error(HTTP_REQUEST);
- test_header_cr_no_lf_error(HTTP_REQUEST);
- test_invalid_header_field_token_error(HTTP_REQUEST);
- test_invalid_header_field_content_error(HTTP_REQUEST);
- test_double_content_length_error(HTTP_RESPONSE);
- test_chunked_content_length_error(HTTP_RESPONSE);
- test_header_cr_no_lf_error(HTTP_RESPONSE);
- test_invalid_header_field_token_error(HTTP_RESPONSE);
- test_invalid_header_field_content_error(HTTP_RESPONSE);
-
- for (i = 0; i < response_count; i++) {
- test_message(&responses[i]);
- }
- for (i = 0; i < response_count; i++) {
- test_message_pause(&responses[i]);
- }
- for (i = 0; i < response_count; i++) {
- if (!responses[i].should_keep_alive) continue;
- for (j = 0; j < response_count; j++) {
- if (!responses[j].should_keep_alive) continue;
- for (k = 0; k < response_count; k++) {
- test_multiple3(&responses[i], &responses[j], &responses[k]);
- }
- }
- }
- test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]);
- test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]);
-
- {
- char * msg = create_large_chunked_message(31337,
- "HTTP/1.0 200 OK\r\n"
- "Transfer-Encoding: chunked\r\n"
- "Content-Type: text/plain\r\n"
- "\r\n");
- struct message large_chunked =
- {.name= "large chunked"
- ,.type= HTTP_RESPONSE
- ,.raw= msg
- ,.should_keep_alive= FALSE
- ,.message_complete_on_eof= FALSE
- ,.http_major= 1
- ,.http_minor= 0
- ,.status_code= 200
- ,.response_status= "OK"
- ,.num_headers= 2
- ,.headers=
- { { "Transfer-Encoding", "chunked" }
- , { "Content-Type", "text/plain" }
- }
- ,.body_size= 31337*1024
- ,.num_chunks_complete= 31338
- };
- for (i = 0; i < MAX_CHUNKS; i++) {
- large_chunked.chunk_lengths[i] = 1024;
- }
- test_message_count_body(&large_chunked);
- free(msg);
- }
- printf("response scan 1/2 ");
- test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
- , &responses[NO_BODY_HTTP10_KA_204]
- , &responses[NO_REASON_PHRASE]
- );
- printf("response scan 2/2 ");
- test_scan( &responses[BONJOUR_MADAME_FR]
- , &responses[UNDERSTORE_HEADER_KEY]
- , &responses[NO_CARRIAGE_RET]
- );
- puts("responses okay");
-
- test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
-
- test_simple("GET / HTTP/1.1\r\n"
- "Test: Düsseldorf\r\n",
- HPE_OK);
-
- test_simple("GET / HTTP/1.1\r\n"
- "Content-Type: text/plain\r\n"
- "Content-Length: 6\r\n"
- "\r\n"
- "fooba",
- HPE_OK);
- static const char *all_methods[] = {
- "DELETE",
- "GET",
- "HEAD",
- "POST",
- "PUT",
-
- "OPTIONS",
- "TRACE",
- "COPY",
- "LOCK",
- "MKCOL",
- "MOVE",
- "PROPFIND",
- "PROPPATCH",
- "SEARCH",
- "UNLOCK",
- "BIND",
- "REBIND",
- "UNBIND",
- "ACL",
- "REPORT",
- "MKACTIVITY",
- "CHECKOUT",
- "MERGE",
- "M-SEARCH",
- "NOTIFY",
- "SUBSCRIBE",
- "UNSUBSCRIBE",
- "PATCH",
- "PURGE",
- "MKCALENDAR",
- "LINK",
- "UNLINK",
- 0 };
- const char **this_method;
- for (this_method = all_methods; *this_method; this_method++) {
- char buf[200];
- sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
- test_simple(buf, HPE_OK);
- }
- static const char *bad_methods[] = {
- "ASDF",
- "C******",
- "COLA",
- "GEM",
- "GETA",
- "M****",
- "MKCOLA",
- "PROPPATCHA",
- "PUN",
- "PX",
- "SA",
- "hello world",
- 0 };
- for (this_method = bad_methods; *this_method; this_method++) {
- char buf[200];
- sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
- test_simple(buf, HPE_INVALID_METHOD);
- }
-
- test_simple("GET / HTTP/1.1\r\n"
- "name\r\n"
- " : value\r\n"
- "\r\n",
- HPE_INVALID_HEADER_TOKEN);
- const char *dumbfuck2 =
- "GET / HTTP/1.1\r\n"
- "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n"
- "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n"
- "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n"
- "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n"
- "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n"
- "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n"
- "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n"
- "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n"
- "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n"
- "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n"
- "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n"
- "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n"
- "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n"
- "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n"
- "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n"
- "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n"
- "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n"
- "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n"
- "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n"
- "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n"
- "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n"
- "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n"
- "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n"
- "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n"
- "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n"
- "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n"
- "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n"
- "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n"
- "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n"
- "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n"
- "\tRA==\r\n"
- "\t-----END CERTIFICATE-----\r\n"
- "\r\n";
- test_simple(dumbfuck2, HPE_OK);
- const char *corrupted_connection =
- "GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection\r\033\065\325eep-Alive\r\n"
- "Accept-Encoding: gzip\r\n"
- "\r\n";
- test_simple(corrupted_connection, HPE_INVALID_HEADER_TOKEN);
- const char *corrupted_header_name =
- "GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "X-Some-Header\r\033\065\325eep-Alive\r\n"
- "Accept-Encoding: gzip\r\n"
- "\r\n";
- test_simple(corrupted_header_name, HPE_INVALID_HEADER_TOKEN);
- #if 0
-
-
-
-
-
- const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n"
- "Accept: */*\r\n"
- "\r\n"
- "HELLO";
- test_simple(bad_get_no_headers_no_body, 0);
- #endif
-
-
- for (i = 0; requests[i].name; i++) {
- test_message(&requests[i]);
- }
- for (i = 0; i < request_count; i++) {
- test_message_pause(&requests[i]);
- }
- for (i = 0; i < request_count; i++) {
- if (!requests[i].should_keep_alive) continue;
- for (j = 0; j < request_count; j++) {
- if (!requests[j].should_keep_alive) continue;
- for (k = 0; k < request_count; k++) {
- test_multiple3(&requests[i], &requests[j], &requests[k]);
- }
- }
- }
- printf("request scan 1/4 ");
- test_scan( &requests[GET_NO_HEADERS_NO_BODY]
- , &requests[GET_ONE_HEADER_NO_BODY]
- , &requests[GET_NO_HEADERS_NO_BODY]
- );
- printf("request scan 2/4 ");
- test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE]
- , &requests[POST_IDENTITY_BODY_WORLD]
- , &requests[GET_FUNKY_CONTENT_LENGTH]
- );
- printf("request scan 3/4 ");
- test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END]
- , &requests[CHUNKED_W_TRAILING_HEADERS]
- , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH]
- );
- printf("request scan 4/4 ");
- test_scan( &requests[QUERY_URL_WITH_QUESTION_MARK_GET]
- , &requests[PREFIX_NEWLINE_GET ]
- , &requests[CONNECT_REQUEST]
- );
- puts("requests okay");
- return 0;
- }
|