HTMIME.c 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427
  1. /* MIME Message Parse HTMIME.c
  2. * ==================
  3. *
  4. * This is RFC 1341-specific code.
  5. * The input stream pushed into this parser is assumed to be
  6. * stripped on CRs, ie lines end with LF, not CR LF.
  7. * (It is easy to change this except for the body part where
  8. * conversion can be slow.)
  9. *
  10. * History:
  11. * Feb 92 Written Tim Berners-Lee, CERN
  12. *
  13. */
  14. #include <HTUtils.h>
  15. #include <HTMIME.h> /* Implemented here */
  16. #include <HTTP.h> /* for redirecting_url */
  17. #include <HTAlert.h>
  18. #include <HTFile.h>
  19. #include <HTCJK.h>
  20. #include <UCMap.h>
  21. #include <UCDefs.h>
  22. #include <UCAux.h>
  23. #include <LYCookie.h>
  24. #include <LYCharSets.h>
  25. #include <LYCharUtils.h>
  26. #include <LYStrings.h>
  27. #include <LYUtils.h>
  28. #include <LYLeaks.h>
  29. /* MIME Object
  30. * -----------
  31. */
  32. typedef enum {
  33. MIME_TRANSPARENT, /* put straight through to target ASAP! */
  34. miBEGINNING_OF_LINE, /* first character and not a continuation */
  35. miA,
  36. miACCEPT_RANGES,
  37. miAGE,
  38. miAL,
  39. miALLOW,
  40. miALTERNATES,
  41. miC,
  42. miCACHE_CONTROL,
  43. miCO,
  44. miCOOKIE,
  45. miCON,
  46. miCONNECTION,
  47. miCONTENT_,
  48. miCONTENT_BASE,
  49. miCONTENT_DISPOSITION,
  50. miCONTENT_ENCODING,
  51. miCONTENT_FEATURES,
  52. miCONTENT_L,
  53. miCONTENT_LANGUAGE,
  54. miCONTENT_LENGTH,
  55. miCONTENT_LOCATION,
  56. miCONTENT_MD5,
  57. miCONTENT_RANGE,
  58. miCONTENT_T,
  59. miCONTENT_TRANSFER_ENCODING,
  60. miCONTENT_TYPE,
  61. miDATE,
  62. miE,
  63. miETAG,
  64. miEXPIRES,
  65. miKEEP_ALIVE,
  66. miL,
  67. miLAST_MODIFIED,
  68. miLINK,
  69. miLOCATION,
  70. miP,
  71. miPR,
  72. miPRAGMA,
  73. miPROXY_AUTHENTICATE,
  74. miPUBLIC,
  75. miR,
  76. miRE,
  77. miREFRESH,
  78. miRETRY_AFTER,
  79. miS,
  80. miSAFE,
  81. miSE,
  82. miSERVER,
  83. miSET_COOKIE,
  84. miSET_COOKIE1,
  85. miSET_COOKIE2,
  86. miT,
  87. miTITLE,
  88. miTRANSFER_ENCODING,
  89. miU,
  90. miUPGRADE,
  91. miURI,
  92. miV,
  93. miVARY,
  94. miVIA,
  95. miW,
  96. miWARNING,
  97. miWWW_AUTHENTICATE,
  98. miSKIP_GET_VALUE, /* Skip space then get value */
  99. miGET_VALUE, /* Get value till white space */
  100. miJUNK_LINE, /* Ignore the rest of this folded line */
  101. miNEWLINE, /* Just found a LF .. maybe continuation */
  102. miCHECK, /* check against check_pointer */
  103. MIME_NET_ASCII, /* Translate from net ascii */
  104. MIME_IGNORE /* Ignore entire file */
  105. /* TRANSPARENT and IGNORE are defined as stg else in _WINDOWS */
  106. } MIME_state;
  107. #define VALUE_SIZE 5120 /* @@@@@@@ Arbitrary? */
  108. struct _HTStream {
  109. const HTStreamClass *isa;
  110. BOOL net_ascii; /* Is input net ascii? */
  111. MIME_state state; /* current state */
  112. MIME_state if_ok; /* got this state if match */
  113. MIME_state field; /* remember which field */
  114. MIME_state fold_state; /* state on a fold */
  115. BOOL head_only; /* only parsing header */
  116. BOOL pickup_redirection; /* parsing for location */
  117. BOOL no_streamstack; /* use sink directly */
  118. const char *check_pointer; /* checking input */
  119. char *value_pointer; /* storing values */
  120. char value[VALUE_SIZE];
  121. HTParentAnchor *anchor; /* Given on creation */
  122. HTStream *sink; /* Given on creation */
  123. char *boundary; /* For multipart */
  124. char *set_cookie; /* Set-Cookie */
  125. char *set_cookie2; /* Set-Cookie2 */
  126. char *location; /* Location */
  127. char *refresh_url; /* "Refresh:" URL */
  128. HTFormat encoding; /* Content-Transfer-Encoding */
  129. char *compression_encoding;
  130. HTFormat format; /* Content-Type */
  131. HTStream *target; /* While writing out */
  132. HTStreamClass targetClass;
  133. HTAtom *targetRep; /* Converting into? */
  134. };
  135. /*
  136. * This function is for trimming off any paired
  137. * open- and close-double quotes from header values.
  138. * It does not parse the string for embedded quotes,
  139. * and will not modify the string unless both the
  140. * first and last characters are double-quotes. - FM
  141. */
  142. void HTMIME_TrimDoubleQuotes(char *value)
  143. {
  144. int i;
  145. char *cp = value;
  146. if (!(cp && *cp) || *cp != '"')
  147. return;
  148. i = strlen(cp);
  149. if (cp[(i - 1)] != '"')
  150. return;
  151. else
  152. cp[(i - 1)] = '\0';
  153. for (i = 0; value[i]; i++)
  154. value[i] = cp[(i + 1)];
  155. }
  156. /*
  157. * Check if the token from "Content-Encoding" corresponds to a compression
  158. * type.
  159. */
  160. static BOOL content_is_compressed(HTStream *me)
  161. {
  162. char *encoding = me->anchor->content_encoding;
  163. BOOL result = (HTEncodingToCompressType(encoding) != cftNone);
  164. CTRACE((tfp, "content is%s compressed\n", result ? "" : " NOT"));
  165. return result;
  166. }
  167. /*
  168. * Strip quotes from a refresh-URL.
  169. */
  170. static void dequote(char *url)
  171. {
  172. int len;
  173. len = strlen(url);
  174. if (*url == '\'' && len > 1 && url[len - 1] == url[0]) {
  175. url[len - 1] = '\0';
  176. while ((url[0] = url[1]) != '\0') {
  177. ++url;
  178. }
  179. }
  180. }
  181. static int pumpData(HTStream *me)
  182. {
  183. if (strchr(HTAtom_name(me->format), ';') != NULL) {
  184. char *cp = NULL, *cp1, *cp2, *cp3 = NULL, *cp4;
  185. CTRACE((tfp, "HTMIME: Extended MIME Content-Type is %s\n",
  186. HTAtom_name(me->format)));
  187. StrAllocCopy(cp, HTAtom_name(me->format));
  188. /*
  189. * Note that the Content-Type value was converted
  190. * to lower case when we loaded into me->format,
  191. * but there may have been a mixed or upper-case
  192. * atom, so we'll force lower-casing again. We
  193. * also stripped spaces and double-quotes, but
  194. * we'll make sure they're still gone from any
  195. * charset parameter we check. - FM
  196. */
  197. LYLowerCase(cp);
  198. if ((cp1 = strchr(cp, ';')) != NULL) {
  199. BOOL chartrans_ok = NO;
  200. if ((cp2 = strstr(cp1, "charset")) != NULL) {
  201. int chndl;
  202. cp2 += 7;
  203. while (*cp2 == ' ' || *cp2 == '=' || *cp2 == '"')
  204. cp2++;
  205. StrAllocCopy(cp3, cp2); /* copy to mutilate more */
  206. for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '"' &&
  207. *cp4 != ';' && *cp4 != ':' &&
  208. !WHITE(*cp4)); cp4++) ; /* do nothing */
  209. *cp4 = '\0';
  210. cp4 = cp3;
  211. chndl = UCGetLYhndl_byMIME(cp3);
  212. if (UCCanTranslateFromTo(chndl,
  213. current_char_set)) {
  214. chartrans_ok = YES;
  215. *cp1 = '\0';
  216. me->format = HTAtom_for(cp);
  217. StrAllocCopy(me->anchor->charset, cp4);
  218. HTAnchor_setUCInfoStage(me->anchor, chndl,
  219. UCT_STAGE_MIME,
  220. UCT_SETBY_MIME);
  221. } else if (chndl < 0) { /* got something but we don't
  222. recognize it */
  223. chndl = UCLYhndl_for_unrec;
  224. if (chndl < 0)
  225. /*
  226. * UCLYhndl_for_unrec not defined :-( fallback to
  227. * UCLYhndl_for_unspec which always valid.
  228. */
  229. chndl = UCLYhndl_for_unspec; /* always >= 0 */
  230. if (UCCanTranslateFromTo(chndl,
  231. current_char_set)) {
  232. chartrans_ok = YES;
  233. *cp1 = '\0';
  234. me->format = HTAtom_for(cp);
  235. HTAnchor_setUCInfoStage(me->anchor, chndl,
  236. UCT_STAGE_MIME,
  237. UCT_SETBY_DEFAULT);
  238. }
  239. } else {
  240. /*
  241. * Something like 'big5' - we cannot translate it, but
  242. * the user may still be able to navigate the links.
  243. */
  244. *cp1 = '\0';
  245. me->format = HTAtom_for(cp);
  246. StrAllocCopy(me->anchor->charset, cp4);
  247. HTAnchor_setUCInfoStage(me->anchor, chndl,
  248. UCT_STAGE_MIME,
  249. UCT_SETBY_MIME);
  250. }
  251. if (chartrans_ok) {
  252. LYUCcharset *p_in =
  253. HTAnchor_getUCInfoStage(me->anchor,
  254. UCT_STAGE_MIME);
  255. LYUCcharset *p_out =
  256. HTAnchor_setUCInfoStage(me->anchor,
  257. current_char_set,
  258. UCT_STAGE_HTEXT,
  259. UCT_SETBY_DEFAULT);
  260. if (!p_out)
  261. /*
  262. * Try again.
  263. */
  264. p_out =
  265. HTAnchor_getUCInfoStage(me->anchor,
  266. UCT_STAGE_HTEXT);
  267. if (!strcmp(p_in->MIMEname,
  268. "x-transparent")) {
  269. HTPassEightBitRaw = TRUE;
  270. HTAnchor_setUCInfoStage(me->anchor,
  271. HTAnchor_getUCLYhndl(me->anchor,
  272. UCT_STAGE_HTEXT),
  273. UCT_STAGE_MIME,
  274. UCT_SETBY_DEFAULT);
  275. }
  276. if (!strcmp(p_out->MIMEname,
  277. "x-transparent")) {
  278. HTPassEightBitRaw = TRUE;
  279. HTAnchor_setUCInfoStage(me->anchor,
  280. HTAnchor_getUCLYhndl(me->anchor,
  281. UCT_STAGE_MIME),
  282. UCT_STAGE_HTEXT,
  283. UCT_SETBY_DEFAULT);
  284. }
  285. if ((p_in->enc != UCT_ENC_CJK)
  286. #ifdef EXP_JAPANESEUTF8_SUPPORT
  287. && ((p_in->enc != UCT_ENC_UTF8)
  288. || (p_out->enc != UCT_ENC_CJK))
  289. #endif
  290. ) {
  291. HTCJK = NOCJK;
  292. if (!(p_in->codepoints &
  293. UCT_CP_SUBSETOF_LAT1) &&
  294. chndl == current_char_set) {
  295. HTPassEightBitRaw = TRUE;
  296. }
  297. } else if (p_out->enc == UCT_ENC_CJK) {
  298. Set_HTCJK(p_in->MIMEname, p_out->MIMEname);
  299. }
  300. } else {
  301. /*
  302. * Cannot translate. If according to some heuristic the
  303. * given charset and the current display character both are
  304. * likely to be like ISO-8859 in structure, pretend we have
  305. * some kind of match.
  306. */
  307. BOOL given_is_8859 =
  308. (BOOL) (!strncmp(cp4, "iso-8859-", 9) &&
  309. isdigit(UCH(cp4[9])));
  310. BOOL given_is_8859like =
  311. (BOOL) (given_is_8859 ||
  312. !strncmp(cp4, "windows-", 8) ||
  313. !strncmp(cp4, "cp12", 4) ||
  314. !strncmp(cp4, "cp-12", 5));
  315. BOOL given_and_display_8859like =
  316. (BOOL) (given_is_8859like &&
  317. (strstr(LYchar_set_names[current_char_set],
  318. "ISO-8859") ||
  319. strstr(LYchar_set_names[current_char_set],
  320. "windows-")));
  321. if (given_and_display_8859like) {
  322. *cp1 = '\0';
  323. me->format = HTAtom_for(cp);
  324. }
  325. if (given_is_8859) {
  326. cp1 = &cp4[10];
  327. while (*cp1 &&
  328. isdigit(UCH(*cp1)))
  329. cp1++;
  330. *cp1 = '\0';
  331. }
  332. if (given_and_display_8859like) {
  333. StrAllocCopy(me->anchor->charset, cp4);
  334. HTPassEightBitRaw = TRUE;
  335. }
  336. HTAlert(*cp4 ? cp4 : me->anchor->charset);
  337. }
  338. FREE(cp3);
  339. } else {
  340. /*
  341. * No charset parameter is present. Ignore all other
  342. * parameters, as we do when charset is present. - FM
  343. */
  344. *cp1 = '\0';
  345. me->format = HTAtom_for(cp);
  346. }
  347. }
  348. FREE(cp);
  349. }
  350. /*
  351. * If we have an Expires header and haven't already set the no_cache
  352. * element for the anchor, check if we should set it based on that header.
  353. * - FM
  354. */
  355. if (me->anchor->no_cache == FALSE &&
  356. me->anchor->expires != NULL) {
  357. if (!strcmp(me->anchor->expires, "0")) {
  358. /*
  359. * The value is zero, which we treat as an absolute no-cache
  360. * directive. - FM
  361. */
  362. me->anchor->no_cache = TRUE;
  363. } else if (me->anchor->date != NULL) {
  364. /*
  365. * We have a Date header, so check if the value is less than or
  366. * equal to that. - FM
  367. */
  368. if (LYmktime(me->anchor->expires, TRUE) <=
  369. LYmktime(me->anchor->date, TRUE)) {
  370. me->anchor->no_cache = TRUE;
  371. }
  372. } else if (LYmktime(me->anchor->expires, FALSE) == 0) {
  373. /*
  374. * We don't have a Date header, and the value is in past for us. -
  375. * FM
  376. */
  377. me->anchor->no_cache = TRUE;
  378. }
  379. }
  380. StrAllocCopy(me->anchor->content_type,
  381. HTAtom_name(me->format));
  382. if (me->set_cookie != NULL || me->set_cookie2 != NULL) {
  383. LYSetCookie(me->set_cookie,
  384. me->set_cookie2,
  385. me->anchor->address);
  386. FREE(me->set_cookie);
  387. FREE(me->set_cookie2);
  388. }
  389. if (me->pickup_redirection) {
  390. if (me->location && *me->location) {
  391. redirecting_url = me->location;
  392. me->location = NULL;
  393. if (me->targetRep != WWW_DEBUG || me->sink)
  394. me->head_only = YES;
  395. } else {
  396. permanent_redirection = FALSE;
  397. if (me->location) {
  398. CTRACE((tfp, "HTTP: 'Location:' is zero-length!\n"));
  399. HTAlert(REDIRECTION_WITH_BAD_LOCATION);
  400. }
  401. CTRACE((tfp, "HTTP: Failed to pick up location.\n"));
  402. if (me->location) {
  403. FREE(me->location);
  404. } else {
  405. HTAlert(REDIRECTION_WITH_NO_LOCATION);
  406. }
  407. }
  408. }
  409. if (me->head_only) {
  410. /* We are done! - kw */
  411. me->state = MIME_IGNORE;
  412. return HT_OK;
  413. }
  414. if (me->no_streamstack) {
  415. me->target = me->sink;
  416. } else {
  417. if (!me->compression_encoding) {
  418. CTRACE((tfp,
  419. "HTMIME: MIME Content-Type is '%s', converting to '%s'\n",
  420. HTAtom_name(me->format), HTAtom_name(me->targetRep)));
  421. } else {
  422. /*
  423. * Change the format to that for "www/compressed" and set up a
  424. * stream to deal with it. - FM
  425. */
  426. CTRACE((tfp, "HTMIME: MIME Content-Type is '%s',\n", HTAtom_name(me->format)));
  427. me->format = HTAtom_for("www/compressed");
  428. CTRACE((tfp, " Treating as '%s'. Converting to '%s'\n",
  429. HTAtom_name(me->format), HTAtom_name(me->targetRep)));
  430. FREE(me->compression_encoding);
  431. }
  432. me->target = HTStreamStack(me->format, me->targetRep,
  433. me->sink, me->anchor);
  434. if (!me->target) {
  435. CTRACE((tfp, "HTMIME: Can't translate! ** \n"));
  436. me->target = me->sink; /* Cheat */
  437. }
  438. }
  439. if (me->target) {
  440. me->targetClass = *me->target->isa;
  441. /*
  442. * Check for encoding and select state from there, someday, but until
  443. * we have the relevant code, from now push straight through. - FM
  444. */
  445. me->state = MIME_TRANSPARENT; /* Pump rest of data right through */
  446. } else {
  447. me->state = MIME_IGNORE; /* What else to do? */
  448. }
  449. if (me->refresh_url != NULL && !content_is_compressed(me)) {
  450. char *url = NULL;
  451. char *num = NULL;
  452. char *txt = NULL;
  453. const char *base = ""; /* FIXME: refresh_url may be relative to doc */
  454. LYParseRefreshURL(me->refresh_url, &num, &url);
  455. if (url != NULL && me->format == WWW_HTML) {
  456. CTRACE((tfp, "Formatting refresh-url as first line of result\n"));
  457. HTSprintf0(&txt, gettext("Refresh: "));
  458. HTSprintf(&txt, gettext("%s seconds "), num);
  459. dequote(url);
  460. HTSprintf(&txt, "<a href=\"%s%s\">%s</a><br>", base, url, url);
  461. CTRACE((tfp, "URL %s%s\n", base, url));
  462. (me->isa->put_string) (me, txt);
  463. free(txt);
  464. }
  465. FREE(num);
  466. FREE(url);
  467. }
  468. return HT_OK;
  469. }
  470. static int dispatchField(HTStream *me)
  471. {
  472. int i, j;
  473. char *cp;
  474. *me->value_pointer = '\0';
  475. cp = me->value_pointer;
  476. while ((cp > me->value) && *(--cp) == ' ') /* S/390 -- gil -- 0146 */
  477. /*
  478. * Trim trailing spaces.
  479. */
  480. *cp = '\0';
  481. switch (me->field) {
  482. case miACCEPT_RANGES:
  483. HTMIME_TrimDoubleQuotes(me->value);
  484. CTRACE((tfp, "HTMIME: PICKED UP Accept-Ranges: '%s'\n",
  485. me->value));
  486. break;
  487. case miAGE:
  488. HTMIME_TrimDoubleQuotes(me->value);
  489. CTRACE((tfp, "HTMIME: PICKED UP Age: '%s'\n",
  490. me->value));
  491. break;
  492. case miALLOW:
  493. HTMIME_TrimDoubleQuotes(me->value);
  494. CTRACE((tfp, "HTMIME: PICKED UP Allow: '%s'\n",
  495. me->value));
  496. break;
  497. case miALTERNATES:
  498. HTMIME_TrimDoubleQuotes(me->value);
  499. CTRACE((tfp, "HTMIME: PICKED UP Alternates: '%s'\n",
  500. me->value));
  501. break;
  502. case miCACHE_CONTROL:
  503. HTMIME_TrimDoubleQuotes(me->value);
  504. CTRACE((tfp, "HTMIME: PICKED UP Cache-Control: '%s'\n",
  505. me->value));
  506. if (!(me->value && *me->value))
  507. break;
  508. /*
  509. * Convert to lowercase and indicate in anchor. - FM
  510. */
  511. LYLowerCase(me->value);
  512. StrAllocCopy(me->anchor->cache_control, me->value);
  513. /*
  514. * Check whether to set no_cache for the anchor. - FM
  515. */
  516. {
  517. char *cp1, *cp0 = me->value;
  518. while ((cp1 = strstr(cp0, "no-cache")) != NULL) {
  519. cp1 += 8;
  520. while (*cp1 != '\0' && WHITE(*cp1))
  521. cp1++;
  522. if (*cp1 == '\0' || *cp1 == ';') {
  523. me->anchor->no_cache = TRUE;
  524. break;
  525. }
  526. cp0 = cp1;
  527. }
  528. if (me->anchor->no_cache == TRUE)
  529. break;
  530. cp0 = me->value;
  531. while ((cp1 = strstr(cp0, "max-age")) != NULL) {
  532. cp1 += 7;
  533. while (*cp1 != '\0' && WHITE(*cp1))
  534. cp1++;
  535. if (*cp1 == '=') {
  536. cp1++;
  537. while (*cp1 != '\0' && WHITE(*cp1))
  538. cp1++;
  539. if (isdigit(UCH(*cp1))) {
  540. cp0 = cp1;
  541. while (isdigit(UCH(*cp1)))
  542. cp1++;
  543. if (*cp0 == '0' && cp1 == (cp0 + 1)) {
  544. me->anchor->no_cache = TRUE;
  545. break;
  546. }
  547. }
  548. }
  549. cp0 = cp1;
  550. }
  551. }
  552. break;
  553. case miCOOKIE:
  554. HTMIME_TrimDoubleQuotes(me->value);
  555. CTRACE((tfp, "HTMIME: PICKED UP Cookie: '%s'\n",
  556. me->value));
  557. break;
  558. case miCONNECTION:
  559. HTMIME_TrimDoubleQuotes(me->value);
  560. CTRACE((tfp, "HTMIME: PICKED UP Connection: '%s'\n",
  561. me->value));
  562. break;
  563. case miCONTENT_BASE:
  564. HTMIME_TrimDoubleQuotes(me->value);
  565. CTRACE((tfp, "HTMIME: PICKED UP Content-Base: '%s'\n",
  566. me->value));
  567. if (!(me->value && *me->value))
  568. break;
  569. /*
  570. * Indicate in anchor. - FM
  571. */
  572. StrAllocCopy(me->anchor->content_base, me->value);
  573. break;
  574. case miCONTENT_DISPOSITION:
  575. HTMIME_TrimDoubleQuotes(me->value);
  576. CTRACE((tfp, "HTMIME: PICKED UP Content-Disposition: '%s'\n",
  577. me->value));
  578. if (!(me->value && *me->value))
  579. break;
  580. /*
  581. * Indicate in anchor. - FM
  582. */
  583. StrAllocCopy(me->anchor->content_disposition, me->value);
  584. /*
  585. * It's not clear yet from existing RFCs and IDs whether we should be
  586. * looking for file;, attachment;, and/or inline; before the
  587. * filename=value, so we'll just search for "filename" followed by '='
  588. * and just hope we get the intended value. It is purely a suggested
  589. * name, anyway. - FM
  590. */
  591. cp = me->anchor->content_disposition;
  592. while (*cp != '\0' && strncasecomp(cp, "filename", 8))
  593. cp++;
  594. if (*cp == '\0')
  595. break;
  596. cp += 8;
  597. while ((*cp != '\0') && (WHITE(*cp) || *cp == '='))
  598. cp++;
  599. if (*cp == '\0')
  600. break;
  601. while (*cp != '\0' && WHITE(*cp))
  602. cp++;
  603. if (*cp == '\0')
  604. break;
  605. StrAllocCopy(me->anchor->SugFname, cp);
  606. if (*me->anchor->SugFname == '"') {
  607. if ((cp = strchr((me->anchor->SugFname + 1),
  608. '"')) != NULL) {
  609. *(cp + 1) = '\0';
  610. HTMIME_TrimDoubleQuotes(me->anchor->SugFname);
  611. } else {
  612. FREE(me->anchor->SugFname);
  613. break;
  614. }
  615. }
  616. cp = me->anchor->SugFname;
  617. while (*cp != '\0' && !WHITE(*cp))
  618. cp++;
  619. *cp = '\0';
  620. if (*me->anchor->SugFname == '\0')
  621. FREE(me->anchor->SugFname);
  622. break;
  623. case miCONTENT_ENCODING:
  624. HTMIME_TrimDoubleQuotes(me->value);
  625. CTRACE((tfp, "HTMIME: PICKED UP Content-Encoding: '%s'\n",
  626. me->value));
  627. if (!(me->value && *me->value) ||
  628. !strcasecomp(me->value, "identity"))
  629. break;
  630. /*
  631. * Convert to lowercase and indicate in anchor. - FM
  632. */
  633. LYLowerCase(me->value);
  634. StrAllocCopy(me->anchor->content_encoding, me->value);
  635. FREE(me->compression_encoding);
  636. if (content_is_compressed(me)) {
  637. /*
  638. * Save it to use as a flag for setting up a "www/compressed"
  639. * target. - FM
  640. */
  641. StrAllocCopy(me->compression_encoding, me->value);
  642. } else {
  643. /*
  644. * Some server indicated "8bit", "7bit" or "binary"
  645. * inappropriately. We'll ignore it. - FM
  646. */
  647. CTRACE((tfp, " Ignoring it!\n"));
  648. }
  649. break;
  650. case miCONTENT_FEATURES:
  651. HTMIME_TrimDoubleQuotes(me->value);
  652. CTRACE((tfp, "HTMIME: PICKED UP Content-Features: '%s'\n",
  653. me->value));
  654. break;
  655. case miCONTENT_LANGUAGE:
  656. HTMIME_TrimDoubleQuotes(me->value);
  657. CTRACE((tfp, "HTMIME: PICKED UP Content-Language: '%s'\n",
  658. me->value));
  659. if (!(me->value && *me->value))
  660. break;
  661. /*
  662. * Convert to lowercase and indicate in anchor. - FM
  663. */
  664. LYLowerCase(me->value);
  665. StrAllocCopy(me->anchor->content_language, me->value);
  666. break;
  667. case miCONTENT_LENGTH:
  668. HTMIME_TrimDoubleQuotes(me->value);
  669. CTRACE((tfp, "HTMIME: PICKED UP Content-Length: '%s'\n",
  670. me->value));
  671. if (!(me->value && *me->value))
  672. break;
  673. /*
  674. * Convert to integer and indicate in anchor. - FM
  675. */
  676. me->anchor->content_length = atoi(me->value);
  677. if (me->anchor->content_length < 0)
  678. me->anchor->content_length = 0;
  679. CTRACE((tfp, " Converted to integer: '%d'\n",
  680. me->anchor->content_length));
  681. break;
  682. case miCONTENT_LOCATION:
  683. HTMIME_TrimDoubleQuotes(me->value);
  684. CTRACE((tfp, "HTMIME: PICKED UP Content-Location: '%s'\n",
  685. me->value));
  686. if (!(me->value && *me->value))
  687. break;
  688. /*
  689. * Indicate in anchor. - FM
  690. */
  691. StrAllocCopy(me->anchor->content_location, me->value);
  692. break;
  693. case miCONTENT_MD5:
  694. HTMIME_TrimDoubleQuotes(me->value);
  695. CTRACE((tfp, "HTMIME: PICKED UP Content-MD5: '%s'\n",
  696. me->value));
  697. if (!(me->value && *me->value))
  698. break;
  699. /*
  700. * Indicate in anchor. - FM
  701. */
  702. StrAllocCopy(me->anchor->content_md5, me->value);
  703. break;
  704. case miCONTENT_RANGE:
  705. HTMIME_TrimDoubleQuotes(me->value);
  706. CTRACE((tfp, "HTMIME: PICKED UP Content-Range: '%s'\n",
  707. me->value));
  708. break;
  709. case miCONTENT_TRANSFER_ENCODING:
  710. HTMIME_TrimDoubleQuotes(me->value);
  711. CTRACE((tfp, "HTMIME: PICKED UP Content-Transfer-Encoding: '%s'\n",
  712. me->value));
  713. if (!(me->value && *me->value))
  714. break;
  715. /*
  716. * Force the Content-Transfer-Encoding value to all lower case. - FM
  717. */
  718. LYLowerCase(me->value);
  719. me->encoding = HTAtom_for(me->value);
  720. break;
  721. case miCONTENT_TYPE:
  722. HTMIME_TrimDoubleQuotes(me->value);
  723. CTRACE((tfp, "HTMIME: PICKED UP Content-Type: '%s'\n",
  724. me->value));
  725. if (!(me->value && *me->value))
  726. break;
  727. /*
  728. * Force the Content-Type value to all lower case and strip spaces and
  729. * double-quotes. - FM
  730. */
  731. for (i = 0, j = 0; me->value[i]; i++) {
  732. if (me->value[i] != ' ' && me->value[i] != '"') {
  733. me->value[j++] = (char) TOLOWER(me->value[i]);
  734. }
  735. }
  736. me->value[j] = '\0';
  737. me->format = HTAtom_for(me->value);
  738. StrAllocCopy(me->anchor->content_type_params, me->value);
  739. break;
  740. case miDATE:
  741. HTMIME_TrimDoubleQuotes(me->value);
  742. CTRACE((tfp, "HTMIME: PICKED UP Date: '%s'\n",
  743. me->value));
  744. if (!(me->value && *me->value))
  745. break;
  746. /*
  747. * Indicate in anchor. - FM
  748. */
  749. StrAllocCopy(me->anchor->date, me->value);
  750. break;
  751. case miETAG:
  752. /* Do not trim double quotes: an entity tag consists of an opaque
  753. * quoted string, possibly prefixed by a weakness indicator.
  754. */
  755. CTRACE((tfp, "HTMIME: PICKED UP ETag: %s\n",
  756. me->value));
  757. if (!(me->value && *me->value))
  758. break;
  759. /*
  760. * Indicate in anchor. - FM
  761. */
  762. StrAllocCopy(me->anchor->ETag, me->value);
  763. break;
  764. case miEXPIRES:
  765. HTMIME_TrimDoubleQuotes(me->value);
  766. CTRACE((tfp, "HTMIME: PICKED UP Expires: '%s'\n",
  767. me->value));
  768. if (!(me->value && *me->value))
  769. break;
  770. /*
  771. * Indicate in anchor. - FM
  772. */
  773. StrAllocCopy(me->anchor->expires, me->value);
  774. break;
  775. case miKEEP_ALIVE:
  776. HTMIME_TrimDoubleQuotes(me->value);
  777. CTRACE((tfp, "HTMIME: PICKED UP Keep-Alive: '%s'\n",
  778. me->value));
  779. break;
  780. case miLAST_MODIFIED:
  781. HTMIME_TrimDoubleQuotes(me->value);
  782. CTRACE((tfp, "HTMIME: PICKED UP Last-Modified: '%s'\n",
  783. me->value));
  784. if (!(me->value && *me->value))
  785. break;
  786. /*
  787. * Indicate in anchor. - FM
  788. */
  789. StrAllocCopy(me->anchor->last_modified, me->value);
  790. break;
  791. case miLINK:
  792. HTMIME_TrimDoubleQuotes(me->value);
  793. CTRACE((tfp, "HTMIME: PICKED UP Link: '%s'\n",
  794. me->value));
  795. break;
  796. case miLOCATION:
  797. HTMIME_TrimDoubleQuotes(me->value);
  798. CTRACE((tfp, "HTMIME: PICKED UP Location: '%s'\n",
  799. me->value));
  800. if (me->pickup_redirection && !me->location) {
  801. StrAllocCopy(me->location, me->value);
  802. } else {
  803. CTRACE((tfp, "HTMIME: *** Ignoring Location!\n"));
  804. }
  805. break;
  806. case miPRAGMA:
  807. HTMIME_TrimDoubleQuotes(me->value);
  808. CTRACE((tfp, "HTMIME: PICKED UP Pragma: '%s'\n",
  809. me->value));
  810. if (!(me->value && *me->value))
  811. break;
  812. /*
  813. * Check whether to set no_cache for the anchor. - FM
  814. */
  815. if (!strcmp(me->value, "no-cache"))
  816. me->anchor->no_cache = TRUE;
  817. break;
  818. case miPROXY_AUTHENTICATE:
  819. HTMIME_TrimDoubleQuotes(me->value);
  820. CTRACE((tfp, "HTMIME: PICKED UP Proxy-Authenticate: '%s'\n",
  821. me->value));
  822. break;
  823. case miPUBLIC:
  824. HTMIME_TrimDoubleQuotes(me->value);
  825. CTRACE((tfp, "HTMIME: PICKED UP Public: '%s'\n",
  826. me->value));
  827. break;
  828. case miREFRESH: /* nonstandard: Netscape */
  829. HTMIME_TrimDoubleQuotes(me->value);
  830. CTRACE((tfp, "HTMIME: PICKED UP Refresh: '%s'\n",
  831. me->value));
  832. StrAllocCopy(me->refresh_url, me->value);
  833. break;
  834. case miRETRY_AFTER:
  835. HTMIME_TrimDoubleQuotes(me->value);
  836. CTRACE((tfp, "HTMIME: PICKED UP Retry-After: '%s'\n",
  837. me->value));
  838. break;
  839. case miSAFE:
  840. HTMIME_TrimDoubleQuotes(me->value);
  841. CTRACE((tfp, "HTMIME: PICKED UP Safe: '%s'\n",
  842. me->value));
  843. if (!(me->value && *me->value))
  844. break;
  845. /*
  846. * Indicate in anchor if "YES" or "TRUE". - FM
  847. */
  848. if (!strcasecomp(me->value, "YES") ||
  849. !strcasecomp(me->value, "TRUE")) {
  850. me->anchor->safe = TRUE;
  851. } else if (!strcasecomp(me->value, "NO") ||
  852. !strcasecomp(me->value, "FALSE")) {
  853. /*
  854. * If server explicitly tells us that it has changed its mind,
  855. * reset flag in anchor. - kw
  856. */
  857. me->anchor->safe = FALSE;
  858. }
  859. break;
  860. case miSERVER:
  861. HTMIME_TrimDoubleQuotes(me->value);
  862. CTRACE((tfp, "HTMIME: PICKED UP Server: '%s'\n",
  863. me->value));
  864. if (!(me->value && *me->value))
  865. break;
  866. /*
  867. * Indicate in anchor. - FM
  868. */
  869. StrAllocCopy(me->anchor->server, me->value);
  870. break;
  871. case miSET_COOKIE1:
  872. HTMIME_TrimDoubleQuotes(me->value);
  873. CTRACE((tfp, "HTMIME: PICKED UP Set-Cookie: '%s'\n",
  874. me->value));
  875. if (me->set_cookie == NULL) {
  876. StrAllocCopy(me->set_cookie, me->value);
  877. } else {
  878. StrAllocCat(me->set_cookie, ", ");
  879. StrAllocCat(me->set_cookie, me->value);
  880. }
  881. break;
  882. case miSET_COOKIE2:
  883. HTMIME_TrimDoubleQuotes(me->value);
  884. CTRACE((tfp, "HTMIME: PICKED UP Set-Cookie2: '%s'\n",
  885. me->value));
  886. if (me->set_cookie2 == NULL) {
  887. StrAllocCopy(me->set_cookie2, me->value);
  888. } else {
  889. StrAllocCat(me->set_cookie2, ", ");
  890. StrAllocCat(me->set_cookie2, me->value);
  891. }
  892. break;
  893. case miTITLE:
  894. HTMIME_TrimDoubleQuotes(me->value);
  895. CTRACE((tfp, "HTMIME: PICKED UP Title: '%s'\n",
  896. me->value));
  897. break;
  898. case miTRANSFER_ENCODING:
  899. HTMIME_TrimDoubleQuotes(me->value);
  900. CTRACE((tfp, "HTMIME: PICKED UP Transfer-Encoding: '%s'\n",
  901. me->value));
  902. break;
  903. case miUPGRADE:
  904. HTMIME_TrimDoubleQuotes(me->value);
  905. CTRACE((tfp, "HTMIME: PICKED UP Upgrade: '%s'\n",
  906. me->value));
  907. break;
  908. case miURI:
  909. HTMIME_TrimDoubleQuotes(me->value);
  910. CTRACE((tfp, "HTMIME: PICKED UP URI: '%s'\n",
  911. me->value));
  912. break;
  913. case miVARY:
  914. HTMIME_TrimDoubleQuotes(me->value);
  915. CTRACE((tfp, "HTMIME: PICKED UP Vary: '%s'\n",
  916. me->value));
  917. break;
  918. case miVIA:
  919. HTMIME_TrimDoubleQuotes(me->value);
  920. CTRACE((tfp, "HTMIME: PICKED UP Via: '%s'\n",
  921. me->value));
  922. break;
  923. case miWARNING:
  924. HTMIME_TrimDoubleQuotes(me->value);
  925. CTRACE((tfp, "HTMIME: PICKED UP Warning: '%s'\n",
  926. me->value));
  927. break;
  928. case miWWW_AUTHENTICATE:
  929. HTMIME_TrimDoubleQuotes(me->value);
  930. CTRACE((tfp, "HTMIME: PICKED UP WWW-Authenticate: '%s'\n",
  931. me->value));
  932. break;
  933. default: /* Should never get here */
  934. return HT_ERROR;
  935. }
  936. return HT_OK;
  937. }
  938. /*_________________________________________________________________________
  939. *
  940. * A C T I O N R O U T I N E S
  941. */
  942. /* Character handling
  943. * ------------------
  944. *
  945. * This is a FSM parser. It ignores field names it does not understand.
  946. * Folded header fields are recognized. Lines without a fieldname at
  947. * the beginning (that are not folded continuation lines) are ignored
  948. * as unknown field names. Fields with empty values are not picked up.
  949. */
  950. static void HTMIME_put_character(HTStream *me,
  951. char c)
  952. {
  953. if (me->state == MIME_TRANSPARENT) {
  954. (*me->targetClass.put_character) (me->target, c); /* MUST BE FAST */
  955. return;
  956. }
  957. /*
  958. * This slightly simple conversion just strips CR and turns LF to newline.
  959. * On unix LF is \n but on Mac \n is CR for example. See NetToText for an
  960. * implementation which preserves single CR or LF.
  961. */
  962. if (me->net_ascii) {
  963. /*
  964. * <sigh> This is evidence that at one time, this code supported
  965. * local character sets other than ASCII. But there is so much
  966. * code in HTTP.c that depends on line_buffer's having been
  967. * translated to local character set that I needed to put the
  968. * FROMASCII translation there, leaving this translation purely
  969. * destructive. -- gil
  970. */
  971. /* S/390 -- gil -- 0118 */
  972. #ifndef NOT_ASCII
  973. c = FROMASCII(c);
  974. #endif /* NOT_ASCII */
  975. if (c == CR)
  976. return;
  977. else if (c == LF)
  978. c = '\n';
  979. }
  980. switch (me->state) {
  981. case MIME_IGNORE:
  982. return;
  983. case MIME_TRANSPARENT: /* Not reached see above */
  984. (*me->targetClass.put_character) (me->target, c);
  985. return;
  986. case MIME_NET_ASCII:
  987. (*me->targetClass.put_character) (me->target, c); /* MUST BE FAST */
  988. return;
  989. case miNEWLINE:
  990. if (c != '\n' && WHITE(c)) { /* Folded line */
  991. me->state = me->fold_state; /* pop state before newline */
  992. if (me->state == miGET_VALUE &&
  993. me->value_pointer && me->value_pointer != me->value &&
  994. !WHITE(*(me->value_pointer - 1))) {
  995. c = ' ';
  996. goto GET_VALUE; /* will add space to value if it fits - kw */
  997. }
  998. break;
  999. } else if (me->fold_state == miGET_VALUE) {
  1000. /* Got a field, and now we know it's complete - so
  1001. * act on it. - kw */
  1002. dispatchField(me);
  1003. }
  1004. /* FALLTHRU */
  1005. case miBEGINNING_OF_LINE:
  1006. me->net_ascii = YES;
  1007. switch (c) {
  1008. case 'a':
  1009. case 'A':
  1010. me->state = miA;
  1011. CTRACE((tfp, "HTMIME: Got 'A' at beginning of line, state now A\n"));
  1012. break;
  1013. case 'c':
  1014. case 'C':
  1015. me->state = miC;
  1016. CTRACE((tfp, "HTMIME: Got 'C' at beginning of line, state now C\n"));
  1017. break;
  1018. case 'd':
  1019. case 'D':
  1020. me->check_pointer = "ate:";
  1021. me->if_ok = miDATE;
  1022. me->state = miCHECK;
  1023. CTRACE((tfp,
  1024. "HTMIME: Got 'D' at beginning of line, checking for 'ate:'\n"));
  1025. break;
  1026. case 'e':
  1027. case 'E':
  1028. me->state = miE;
  1029. CTRACE((tfp, "HTMIME: Got 'E' at beginning of line, state now E\n"));
  1030. break;
  1031. case 'k':
  1032. case 'K':
  1033. me->check_pointer = "eep-alive:";
  1034. me->if_ok = miKEEP_ALIVE;
  1035. me->state = miCHECK;
  1036. CTRACE((tfp,
  1037. "HTMIME: Got 'K' at beginning of line, checking for 'eep-alive:'\n"));
  1038. break;
  1039. case 'l':
  1040. case 'L':
  1041. me->state = miL;
  1042. CTRACE((tfp, "HTMIME: Got 'L' at beginning of line, state now L\n"));
  1043. break;
  1044. case 'p':
  1045. case 'P':
  1046. me->state = miP;
  1047. CTRACE((tfp, "HTMIME: Got 'P' at beginning of line, state now P\n"));
  1048. break;
  1049. case 'r':
  1050. case 'R':
  1051. me->state = miR;
  1052. CTRACE((tfp, "HTMIME: Got 'R' at beginning of line, state now R\n"));
  1053. break;
  1054. case 's':
  1055. case 'S':
  1056. me->state = miS;
  1057. CTRACE((tfp, "HTMIME: Got 'S' at beginning of line, state now S\n"));
  1058. break;
  1059. case 't':
  1060. case 'T':
  1061. me->state = miT;
  1062. CTRACE((tfp, "HTMIME: Got 'T' at beginning of line, state now T\n"));
  1063. break;
  1064. case 'u':
  1065. case 'U':
  1066. me->state = miU;
  1067. CTRACE((tfp, "HTMIME: Got 'U' at beginning of line, state now U\n"));
  1068. break;
  1069. case 'v':
  1070. case 'V':
  1071. me->state = miV;
  1072. CTRACE((tfp, "HTMIME: Got 'V' at beginning of line, state now V\n"));
  1073. break;
  1074. case 'w':
  1075. case 'W':
  1076. me->state = miW;
  1077. CTRACE((tfp, "HTMIME: Got 'W' at beginning of line, state now W\n"));
  1078. break;
  1079. case '\n': /* Blank line: End of Header! */
  1080. {
  1081. me->net_ascii = NO;
  1082. pumpData(me);
  1083. }
  1084. break;
  1085. default:
  1086. goto bad_field_name;
  1087. } /* switch on character */
  1088. break;
  1089. case miA: /* Check for 'c','g' or 'l' */
  1090. switch (c) {
  1091. case 'c':
  1092. case 'C':
  1093. me->check_pointer = "cept-ranges:";
  1094. me->if_ok = miACCEPT_RANGES;
  1095. me->state = miCHECK;
  1096. CTRACE((tfp,
  1097. "HTMIME: Was A, found C, checking for 'cept-ranges:'\n"));
  1098. break;
  1099. case 'g':
  1100. case 'G':
  1101. me->check_pointer = "e:";
  1102. me->if_ok = miAGE;
  1103. me->state = miCHECK;
  1104. CTRACE((tfp, "HTMIME: Was A, found G, checking for 'e:'\n"));
  1105. break;
  1106. case 'l':
  1107. case 'L':
  1108. me->state = miAL;
  1109. CTRACE((tfp, "HTMIME: Was A, found L, state now AL'\n"));
  1110. break;
  1111. default:
  1112. CTRACE((tfp,
  1113. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1114. c, "'g' or 'l'"));
  1115. goto bad_field_name;
  1116. } /* switch on character */
  1117. break;
  1118. case miAL: /* Check for 'l' or 't' */
  1119. switch (c) {
  1120. case 'l':
  1121. case 'L':
  1122. me->check_pointer = "ow:";
  1123. me->if_ok = miALLOW;
  1124. me->state = miCHECK;
  1125. CTRACE((tfp, "HTMIME: Was AL, found L, checking for 'ow:'\n"));
  1126. break;
  1127. case 't':
  1128. case 'T':
  1129. me->check_pointer = "ernates:";
  1130. me->if_ok = miALTERNATES;
  1131. me->state = miCHECK;
  1132. CTRACE((tfp, "HTMIME: Was AL, found T, checking for 'ernates:'\n"));
  1133. break;
  1134. default:
  1135. CTRACE((tfp,
  1136. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1137. c, "'l' or 't'"));
  1138. goto bad_field_name;
  1139. } /* switch on character */
  1140. break;
  1141. case miC: /* Check for 'a' or 'o' */
  1142. switch (c) {
  1143. case 'a':
  1144. case 'A':
  1145. me->check_pointer = "che-control:";
  1146. me->if_ok = miCACHE_CONTROL;
  1147. me->state = miCHECK;
  1148. CTRACE((tfp,
  1149. "HTMIME: Was C, found A, checking for 'che-control:'\n"));
  1150. break;
  1151. case 'o':
  1152. case 'O':
  1153. me->state = miCO;
  1154. CTRACE((tfp, "HTMIME: Was C, found O, state now CO'\n"));
  1155. break;
  1156. default:
  1157. CTRACE((tfp,
  1158. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1159. c, "'a' or 'o'"));
  1160. goto bad_field_name;
  1161. } /* switch on character */
  1162. break;
  1163. case miCO: /* Check for 'n' or 'o' */
  1164. switch (c) {
  1165. case 'n':
  1166. case 'N':
  1167. me->state = miCON;
  1168. CTRACE((tfp, "HTMIME: Was CO, found N, state now CON\n"));
  1169. break;
  1170. case 'o':
  1171. case 'O':
  1172. me->check_pointer = "kie:";
  1173. me->if_ok = miCOOKIE;
  1174. me->state = miCHECK;
  1175. CTRACE((tfp, "HTMIME: Was CO, found O, checking for 'kie:'\n"));
  1176. break;
  1177. default:
  1178. CTRACE((tfp,
  1179. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1180. c, "'n' or 'o'"));
  1181. goto bad_field_name;
  1182. } /* switch on character */
  1183. break;
  1184. case miCON: /* Check for 'n' or 't' */
  1185. switch (c) {
  1186. case 'n':
  1187. case 'N':
  1188. me->check_pointer = "ection:";
  1189. me->if_ok = miCONNECTION;
  1190. me->state = miCHECK;
  1191. CTRACE((tfp, "HTMIME: Was CON, found N, checking for 'ection:'\n"));
  1192. break;
  1193. case 't':
  1194. case 'T':
  1195. me->check_pointer = "ent-";
  1196. me->if_ok = miCONTENT_;
  1197. me->state = miCHECK;
  1198. CTRACE((tfp, "HTMIME: Was CON, found T, checking for 'ent-'\n"));
  1199. break;
  1200. default:
  1201. CTRACE((tfp,
  1202. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1203. c, "'n' or 't'"));
  1204. goto bad_field_name;
  1205. } /* switch on character */
  1206. break;
  1207. case miE: /* Check for 't' or 'x' */
  1208. switch (c) {
  1209. case 't':
  1210. case 'T':
  1211. me->check_pointer = "ag:";
  1212. me->if_ok = miETAG;
  1213. me->state = miCHECK;
  1214. CTRACE((tfp, "HTMIME: Was E, found T, checking for 'ag:'\n"));
  1215. break;
  1216. case 'x':
  1217. case 'X':
  1218. me->check_pointer = "pires:";
  1219. me->if_ok = miEXPIRES;
  1220. me->state = miCHECK;
  1221. CTRACE((tfp, "HTMIME: Was E, found X, checking for 'pires:'\n"));
  1222. break;
  1223. default:
  1224. CTRACE((tfp,
  1225. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1226. c, "'t' or 'x'"));
  1227. goto bad_field_name;
  1228. } /* switch on character */
  1229. break;
  1230. case miL: /* Check for 'a', 'i' or 'o' */
  1231. switch (c) {
  1232. case 'a':
  1233. case 'A':
  1234. me->check_pointer = "st-modified:";
  1235. me->if_ok = miLAST_MODIFIED;
  1236. me->state = miCHECK;
  1237. CTRACE((tfp,
  1238. "HTMIME: Was L, found A, checking for 'st-modified:'\n"));
  1239. break;
  1240. case 'i':
  1241. case 'I':
  1242. me->check_pointer = "nk:";
  1243. me->if_ok = miLINK;
  1244. me->state = miCHECK;
  1245. CTRACE((tfp, "HTMIME: Was L, found I, checking for 'nk:'\n"));
  1246. break;
  1247. case 'o':
  1248. case 'O':
  1249. me->check_pointer = "cation:";
  1250. me->if_ok = miLOCATION;
  1251. me->state = miCHECK;
  1252. CTRACE((tfp, "HTMIME: Was L, found O, checking for 'cation:'\n"));
  1253. break;
  1254. default:
  1255. CTRACE((tfp,
  1256. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1257. c, "'a', 'i' or 'o'"));
  1258. goto bad_field_name;
  1259. } /* switch on character */
  1260. break;
  1261. case miP: /* Check for 'r' or 'u' */
  1262. switch (c) {
  1263. case 'r':
  1264. case 'R':
  1265. me->state = miPR;
  1266. CTRACE((tfp, "HTMIME: Was P, found R, state now PR'\n"));
  1267. break;
  1268. case 'u':
  1269. case 'U':
  1270. me->check_pointer = "blic:";
  1271. me->if_ok = miPUBLIC;
  1272. me->state = miCHECK;
  1273. CTRACE((tfp, "HTMIME: Was P, found U, checking for 'blic:'\n"));
  1274. break;
  1275. default:
  1276. CTRACE((tfp,
  1277. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1278. c, "'r' or 'u'"));
  1279. goto bad_field_name;
  1280. } /* switch on character */
  1281. break;
  1282. case miPR: /* Check for 'a' or 'o' */
  1283. switch (c) {
  1284. case 'a':
  1285. case 'A':
  1286. me->check_pointer = "gma:";
  1287. me->if_ok = miPRAGMA;
  1288. me->state = miCHECK;
  1289. CTRACE((tfp, "HTMIME: Was PR, found A, checking for 'gma'\n"));
  1290. break;
  1291. case 'o':
  1292. case 'O':
  1293. me->check_pointer = "xy-authenticate:";
  1294. me->if_ok = miPROXY_AUTHENTICATE;
  1295. me->state = miCHECK;
  1296. CTRACE((tfp,
  1297. "HTMIME: Was PR, found O, checking for 'xy-authenticate'\n"));
  1298. break;
  1299. default:
  1300. CTRACE((tfp,
  1301. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1302. c, "'a' or 'o'"));
  1303. goto bad_field_name;
  1304. } /* switch on character */
  1305. break;
  1306. case miR: /* Check for 'e' */
  1307. switch (c) {
  1308. case 'e':
  1309. case 'E':
  1310. me->state = miRE;
  1311. CTRACE((tfp, "HTMIME: Was R, found E\n"));
  1312. break;
  1313. default:
  1314. CTRACE((tfp,
  1315. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1316. c, "'e'"));
  1317. goto bad_field_name;
  1318. } /* switch on character */
  1319. break;
  1320. case miRE: /* Check for 'a' or 'o' */
  1321. switch (c) {
  1322. case 'f':
  1323. case 'F': /* nonstandard: Netscape */
  1324. me->check_pointer = "resh:";
  1325. me->if_ok = miREFRESH;
  1326. me->state = miCHECK;
  1327. CTRACE((tfp, "HTMIME: Was RE, found F, checking for '%s'\n", me->check_pointer));
  1328. break;
  1329. case 't':
  1330. case 'T':
  1331. me->check_pointer = "ry-after:";
  1332. me->if_ok = miRETRY_AFTER;
  1333. me->state = miCHECK;
  1334. CTRACE((tfp, "HTMIME: Was RE, found T, checking for '%s'\n", me->check_pointer));
  1335. break;
  1336. default:
  1337. CTRACE((tfp,
  1338. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1339. c, "'f' or 't'"));
  1340. goto bad_field_name;
  1341. } /* switch on character */
  1342. break;
  1343. case miS: /* Check for 'a' or 'e' */
  1344. switch (c) {
  1345. case 'a':
  1346. case 'A':
  1347. me->check_pointer = "fe:";
  1348. me->if_ok = miSAFE;
  1349. me->state = miCHECK;
  1350. CTRACE((tfp, "HTMIME: Was S, found A, checking for 'fe:'\n"));
  1351. break;
  1352. case 'e':
  1353. case 'E':
  1354. me->state = miSE;
  1355. CTRACE((tfp, "HTMIME: Was S, found E, state now SE'\n"));
  1356. break;
  1357. default:
  1358. CTRACE((tfp,
  1359. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1360. c, "'a' or 'e'"));
  1361. goto bad_field_name;
  1362. } /* switch on character */
  1363. break;
  1364. case miSE: /* Check for 'r' or 't' */
  1365. switch (c) {
  1366. case 'r':
  1367. case 'R':
  1368. me->check_pointer = "ver:";
  1369. me->if_ok = miSERVER;
  1370. me->state = miCHECK;
  1371. CTRACE((tfp, "HTMIME: Was SE, found R, checking for 'ver'\n"));
  1372. break;
  1373. case 't':
  1374. case 'T':
  1375. me->check_pointer = "-cookie";
  1376. me->if_ok = miSET_COOKIE;
  1377. me->state = miCHECK;
  1378. CTRACE((tfp, "HTMIME: Was SE, found T, checking for '-cookie'\n"));
  1379. break;
  1380. default:
  1381. CTRACE((tfp,
  1382. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1383. c, "'r' or 't'"));
  1384. goto bad_field_name;
  1385. } /* switch on character */
  1386. break;
  1387. case miSET_COOKIE: /* Check for ':' or '2' */
  1388. switch (c) {
  1389. case ':':
  1390. me->field = miSET_COOKIE1; /* remember it */
  1391. me->state = miSKIP_GET_VALUE;
  1392. CTRACE((tfp, "HTMIME: Was SET_COOKIE, found :, processing\n"));
  1393. break;
  1394. case '2':
  1395. me->check_pointer = ":";
  1396. me->if_ok = miSET_COOKIE2;
  1397. me->state = miCHECK;
  1398. CTRACE((tfp, "HTMIME: Was SET_COOKIE, found 2, checking for ':'\n"));
  1399. break;
  1400. default:
  1401. CTRACE((tfp,
  1402. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1403. c, "':' or '2'"));
  1404. goto bad_field_name;
  1405. } /* switch on character */
  1406. break;
  1407. case miT: /* Check for 'i' or 'r' */
  1408. switch (c) {
  1409. case 'i':
  1410. case 'I':
  1411. me->check_pointer = "tle:";
  1412. me->if_ok = miTITLE;
  1413. me->state = miCHECK;
  1414. CTRACE((tfp, "HTMIME: Was T, found I, checking for 'tle:'\n"));
  1415. break;
  1416. case 'r':
  1417. case 'R':
  1418. me->check_pointer = "ansfer-encoding:";
  1419. me->if_ok = miTRANSFER_ENCODING;
  1420. me->state = miCHECK;
  1421. CTRACE((tfp,
  1422. "HTMIME: Was T, found R, checking for 'ansfer-encoding'\n"));
  1423. break;
  1424. default:
  1425. CTRACE((tfp,
  1426. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1427. c, "'i' or 'r'"));
  1428. goto bad_field_name;
  1429. } /* switch on character */
  1430. break;
  1431. case miU: /* Check for 'p' or 'r' */
  1432. switch (c) {
  1433. case 'p':
  1434. case 'P':
  1435. me->check_pointer = "grade:";
  1436. me->if_ok = miUPGRADE;
  1437. me->state = miCHECK;
  1438. CTRACE((tfp, "HTMIME: Was U, found P, checking for 'grade:'\n"));
  1439. break;
  1440. case 'r':
  1441. case 'R':
  1442. me->check_pointer = "i:";
  1443. me->if_ok = miURI;
  1444. me->state = miCHECK;
  1445. CTRACE((tfp, "HTMIME: Was U, found R, checking for 'i:'\n"));
  1446. break;
  1447. default:
  1448. CTRACE((tfp,
  1449. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1450. c, "'p' or 'r'"));
  1451. goto bad_field_name;
  1452. } /* switch on character */
  1453. break;
  1454. case miV: /* Check for 'a' or 'i' */
  1455. switch (c) {
  1456. case 'a':
  1457. case 'A':
  1458. me->check_pointer = "ry:";
  1459. me->if_ok = miVARY;
  1460. me->state = miCHECK;
  1461. CTRACE((tfp, "HTMIME: Was V, found A, checking for 'ry:'\n"));
  1462. break;
  1463. case 'i':
  1464. case 'I':
  1465. me->check_pointer = "a:";
  1466. me->if_ok = miVIA;
  1467. me->state = miCHECK;
  1468. CTRACE((tfp, "HTMIME: Was V, found I, checking for 'a:'\n"));
  1469. break;
  1470. default:
  1471. CTRACE((tfp,
  1472. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1473. c, "'a' or 'i'"));
  1474. goto bad_field_name;
  1475. } /* switch on character */
  1476. break;
  1477. case miW: /* Check for 'a' or 'w' */
  1478. switch (c) {
  1479. case 'a':
  1480. case 'A':
  1481. me->check_pointer = "rning:";
  1482. me->if_ok = miWARNING;
  1483. me->state = miCHECK;
  1484. CTRACE((tfp, "HTMIME: Was W, found A, checking for 'rning:'\n"));
  1485. break;
  1486. case 'w':
  1487. case 'W':
  1488. me->check_pointer = "w-authenticate:";
  1489. me->if_ok = miWWW_AUTHENTICATE;
  1490. me->state = miCHECK;
  1491. CTRACE((tfp,
  1492. "HTMIME: Was W, found W, checking for 'w-authenticate:'\n"));
  1493. break;
  1494. default:
  1495. CTRACE((tfp,
  1496. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1497. c, "'a' or 'w'"));
  1498. goto bad_field_name;
  1499. } /* switch on character */
  1500. break;
  1501. case miCHECK: /* Check against string */
  1502. if (TOLOWER(c) == *(me->check_pointer)++) {
  1503. if (!*me->check_pointer)
  1504. me->state = me->if_ok;
  1505. } else { /* Error */
  1506. CTRACE((tfp,
  1507. "HTMIME: Bad character `%c' found where `%s' expected\n",
  1508. c, me->check_pointer - 1));
  1509. goto bad_field_name;
  1510. }
  1511. break;
  1512. case miCONTENT_:
  1513. CTRACE((tfp, "HTMIME: in case CONTENT_\n"));
  1514. switch (c) {
  1515. case 'b':
  1516. case 'B':
  1517. me->check_pointer = "ase:";
  1518. me->if_ok = miCONTENT_BASE;
  1519. me->state = miCHECK;
  1520. CTRACE((tfp,
  1521. "HTMIME: Was CONTENT_, found B, checking for 'ase:'\n"));
  1522. break;
  1523. case 'd':
  1524. case 'D':
  1525. me->check_pointer = "isposition:";
  1526. me->if_ok = miCONTENT_DISPOSITION;
  1527. me->state = miCHECK;
  1528. CTRACE((tfp,
  1529. "HTMIME: Was CONTENT_, found D, checking for 'isposition:'\n"));
  1530. break;
  1531. case 'e':
  1532. case 'E':
  1533. me->check_pointer = "ncoding:";
  1534. me->if_ok = miCONTENT_ENCODING;
  1535. me->state = miCHECK;
  1536. CTRACE((tfp,
  1537. "HTMIME: Was CONTENT_, found E, checking for 'ncoding:'\n"));
  1538. break;
  1539. case 'f':
  1540. case 'F':
  1541. me->check_pointer = "eatures:";
  1542. me->if_ok = miCONTENT_FEATURES;
  1543. me->state = miCHECK;
  1544. CTRACE((tfp,
  1545. "HTMIME: Was CONTENT_, found F, checking for 'eatures:'\n"));
  1546. break;
  1547. case 'l':
  1548. case 'L':
  1549. me->state = miCONTENT_L;
  1550. CTRACE((tfp,
  1551. "HTMIME: Was CONTENT_, found L, state now CONTENT_L\n"));
  1552. break;
  1553. case 'm':
  1554. case 'M':
  1555. me->check_pointer = "d5:";
  1556. me->if_ok = miCONTENT_MD5;
  1557. me->state = miCHECK;
  1558. CTRACE((tfp, "HTMIME: Was CONTENT_, found M, checking for 'd5:'\n"));
  1559. break;
  1560. case 'r':
  1561. case 'R':
  1562. me->check_pointer = "ange:";
  1563. me->if_ok = miCONTENT_RANGE;
  1564. me->state = miCHECK;
  1565. CTRACE((tfp,
  1566. "HTMIME: Was CONTENT_, found R, checking for 'ange:'\n"));
  1567. break;
  1568. case 't':
  1569. case 'T':
  1570. me->state = miCONTENT_T;
  1571. CTRACE((tfp,
  1572. "HTMIME: Was CONTENT_, found T, state now CONTENT_T\n"));
  1573. break;
  1574. default:
  1575. CTRACE((tfp, "HTMIME: Was CONTENT_, found nothing; bleah\n"));
  1576. goto bad_field_name;
  1577. } /* switch on character */
  1578. break;
  1579. case miCONTENT_L:
  1580. CTRACE((tfp, "HTMIME: in case CONTENT_L\n"));
  1581. switch (c) {
  1582. case 'a':
  1583. case 'A':
  1584. me->check_pointer = "nguage:";
  1585. me->if_ok = miCONTENT_LANGUAGE;
  1586. me->state = miCHECK;
  1587. CTRACE((tfp,
  1588. "HTMIME: Was CONTENT_L, found A, checking for 'nguage:'\n"));
  1589. break;
  1590. case 'e':
  1591. case 'E':
  1592. me->check_pointer = "ngth:";
  1593. me->if_ok = miCONTENT_LENGTH;
  1594. me->state = miCHECK;
  1595. CTRACE((tfp,
  1596. "HTMIME: Was CONTENT_L, found E, checking for 'ngth:'\n"));
  1597. break;
  1598. case 'o':
  1599. case 'O':
  1600. me->check_pointer = "cation:";
  1601. me->if_ok = miCONTENT_LOCATION;
  1602. me->state = miCHECK;
  1603. CTRACE((tfp,
  1604. "HTMIME: Was CONTENT_L, found O, checking for 'cation:'\n"));
  1605. break;
  1606. default:
  1607. CTRACE((tfp, "HTMIME: Was CONTENT_L, found nothing; bleah\n"));
  1608. goto bad_field_name;
  1609. } /* switch on character */
  1610. break;
  1611. case miCONTENT_T:
  1612. CTRACE((tfp, "HTMIME: in case CONTENT_T\n"));
  1613. switch (c) {
  1614. case 'r':
  1615. case 'R':
  1616. me->check_pointer = "ansfer-encoding:";
  1617. me->if_ok = miCONTENT_TRANSFER_ENCODING;
  1618. me->state = miCHECK;
  1619. CTRACE((tfp,
  1620. "HTMIME: Was CONTENT_T, found R, checking for 'ansfer-encoding:'\n"));
  1621. break;
  1622. case 'y':
  1623. case 'Y':
  1624. me->check_pointer = "pe:";
  1625. me->if_ok = miCONTENT_TYPE;
  1626. me->state = miCHECK;
  1627. CTRACE((tfp,
  1628. "HTMIME: Was CONTENT_T, found Y, checking for 'pe:'\n"));
  1629. break;
  1630. default:
  1631. CTRACE((tfp, "HTMIME: Was CONTENT_T, found nothing; bleah\n"));
  1632. goto bad_field_name;
  1633. } /* switch on character */
  1634. break;
  1635. case miACCEPT_RANGES:
  1636. case miAGE:
  1637. case miALLOW:
  1638. case miALTERNATES:
  1639. case miCACHE_CONTROL:
  1640. case miCOOKIE:
  1641. case miCONNECTION:
  1642. case miCONTENT_BASE:
  1643. case miCONTENT_DISPOSITION:
  1644. case miCONTENT_ENCODING:
  1645. case miCONTENT_FEATURES:
  1646. case miCONTENT_LANGUAGE:
  1647. case miCONTENT_LENGTH:
  1648. case miCONTENT_LOCATION:
  1649. case miCONTENT_MD5:
  1650. case miCONTENT_RANGE:
  1651. case miCONTENT_TRANSFER_ENCODING:
  1652. case miCONTENT_TYPE:
  1653. case miDATE:
  1654. case miETAG:
  1655. case miEXPIRES:
  1656. case miKEEP_ALIVE:
  1657. case miLAST_MODIFIED:
  1658. case miLINK:
  1659. case miLOCATION:
  1660. case miPRAGMA:
  1661. case miPROXY_AUTHENTICATE:
  1662. case miPUBLIC:
  1663. case miREFRESH:
  1664. case miRETRY_AFTER:
  1665. case miSAFE:
  1666. case miSERVER:
  1667. case miSET_COOKIE1:
  1668. case miSET_COOKIE2:
  1669. case miTITLE:
  1670. case miTRANSFER_ENCODING:
  1671. case miUPGRADE:
  1672. case miURI:
  1673. case miVARY:
  1674. case miVIA:
  1675. case miWARNING:
  1676. case miWWW_AUTHENTICATE:
  1677. me->field = me->state; /* remember it */
  1678. me->state = miSKIP_GET_VALUE;
  1679. /* Fall through! */
  1680. case miSKIP_GET_VALUE:
  1681. if (c == '\n') {
  1682. me->fold_state = me->state;
  1683. me->state = miNEWLINE;
  1684. break;
  1685. }
  1686. if (WHITE(c))
  1687. /*
  1688. * Skip white space.
  1689. */
  1690. break;
  1691. me->value_pointer = me->value;
  1692. me->state = miGET_VALUE;
  1693. /* Fall through to store first character */
  1694. case miGET_VALUE:
  1695. GET_VALUE:
  1696. if (c != '\n') { /* Not end of line */
  1697. if (me->value_pointer < me->value + VALUE_SIZE - 1) {
  1698. *me->value_pointer++ = c;
  1699. break;
  1700. } else {
  1701. goto value_too_long;
  1702. }
  1703. }
  1704. /* Fall through (if end of line) */
  1705. case miJUNK_LINE:
  1706. if (c == '\n') {
  1707. me->fold_state = me->state;
  1708. me->state = miNEWLINE;
  1709. }
  1710. break;
  1711. } /* switch on state */
  1712. #ifdef EXP_HTTP_HEADERS
  1713. HTChunkPutc(&me->anchor->http_headers, c);
  1714. if (me->state == MIME_TRANSPARENT) {
  1715. HTChunkTerminate(&me->anchor->http_headers);
  1716. CTRACE((tfp, "Server Headers:\n%.*s\n",
  1717. me->anchor->http_headers.size,
  1718. me->anchor->http_headers.data));
  1719. CTRACE((tfp, "Server Content-Type:%s\n",
  1720. me->anchor->content_type_params));
  1721. }
  1722. #endif
  1723. return;
  1724. value_too_long:
  1725. CTRACE((tfp, "HTMIME: *** Syntax error. (string too long)\n"));
  1726. bad_field_name: /* Ignore it */
  1727. me->state = miJUNK_LINE;
  1728. #ifdef EXP_HTTP_HEADERS
  1729. HTChunkPutc(&me->anchor->http_headers, c);
  1730. #endif
  1731. return;
  1732. }
  1733. /* String handling
  1734. * ---------------
  1735. *
  1736. * Strings must be smaller than this buffer size.
  1737. */
  1738. static void HTMIME_put_string(HTStream *me,
  1739. const char *s)
  1740. {
  1741. const char *p;
  1742. if (me->state == MIME_TRANSPARENT) { /* Optimisation */
  1743. (*me->targetClass.put_string) (me->target, s);
  1744. } else if (me->state != MIME_IGNORE) {
  1745. CTRACE((tfp, "HTMIME: %s\n", s));
  1746. for (p = s; *p; p++)
  1747. HTMIME_put_character(me, *p);
  1748. }
  1749. }
  1750. /* Buffer write. Buffers can (and should!) be big.
  1751. * ------------
  1752. */
  1753. static void HTMIME_write(HTStream *me,
  1754. const char *s,
  1755. int l)
  1756. {
  1757. const char *p;
  1758. if (me->state == MIME_TRANSPARENT) { /* Optimisation */
  1759. (*me->targetClass.put_block) (me->target, s, l);
  1760. } else {
  1761. CTRACE((tfp, "HTMIME: %.*s\n", l, s));
  1762. for (p = s; p < s + l; p++)
  1763. HTMIME_put_character(me, *p);
  1764. }
  1765. }
  1766. /* Free an HTML object
  1767. * -------------------
  1768. *
  1769. */
  1770. static void HTMIME_free(HTStream *me)
  1771. {
  1772. if (me) {
  1773. FREE(me->location);
  1774. FREE(me->compression_encoding);
  1775. if (me->target)
  1776. (*me->targetClass._free) (me->target);
  1777. FREE(me);
  1778. }
  1779. }
  1780. /* End writing
  1781. */
  1782. static void HTMIME_abort(HTStream *me,
  1783. HTError e)
  1784. {
  1785. if (me) {
  1786. FREE(me->location);
  1787. FREE(me->compression_encoding);
  1788. if (me->target)
  1789. (*me->targetClass._abort) (me->target, e);
  1790. FREE(me);
  1791. }
  1792. }
  1793. /* Structured Object Class
  1794. * -----------------------
  1795. */
  1796. static const HTStreamClass HTMIME =
  1797. {
  1798. "MIMEParser",
  1799. HTMIME_free,
  1800. HTMIME_abort,
  1801. HTMIME_put_character,
  1802. HTMIME_put_string,
  1803. HTMIME_write
  1804. };
  1805. /* Subclass-specific Methods
  1806. * -------------------------
  1807. */
  1808. HTStream *HTMIMEConvert(HTPresentation *pres,
  1809. HTParentAnchor *anchor,
  1810. HTStream *sink)
  1811. {
  1812. HTStream *me;
  1813. me = typecalloc(HTStream);
  1814. if (me == NULL)
  1815. outofmem(__FILE__, "HTMIMEConvert");
  1816. me->isa = &HTMIME;
  1817. me->sink = sink;
  1818. me->anchor = anchor;
  1819. me->anchor->safe = FALSE;
  1820. me->anchor->no_cache = FALSE;
  1821. FREE(me->anchor->cache_control);
  1822. FREE(me->anchor->SugFname);
  1823. FREE(me->anchor->charset);
  1824. #ifdef EXP_HTTP_HEADERS
  1825. HTChunkClear(&me->anchor->http_headers);
  1826. HTChunkInit(&me->anchor->http_headers, 128);
  1827. #endif
  1828. FREE(me->anchor->content_type_params);
  1829. FREE(me->anchor->content_language);
  1830. FREE(me->anchor->content_encoding);
  1831. FREE(me->anchor->content_base);
  1832. FREE(me->anchor->content_disposition);
  1833. FREE(me->anchor->content_location);
  1834. FREE(me->anchor->content_md5);
  1835. me->anchor->content_length = 0;
  1836. FREE(me->anchor->date);
  1837. FREE(me->anchor->expires);
  1838. FREE(me->anchor->last_modified);
  1839. FREE(me->anchor->ETag);
  1840. FREE(me->anchor->server);
  1841. me->target = NULL;
  1842. me->state = miBEGINNING_OF_LINE;
  1843. /*
  1844. * Sadly enough, change this to always default to WWW_HTML to parse all
  1845. * text as HTML for the users.
  1846. * GAB 06-30-94
  1847. * Thanks to Robert Rowland robert@cyclops.pei.edu
  1848. *
  1849. * After discussion of the correct handline, should be application/octet-
  1850. * stream or unknown; causing servers to send a correct content type.
  1851. *
  1852. * The consequence of using WWW_UNKNOWN is that you end up downloading as a
  1853. * binary file what 99.9% of the time is an HTML file, which should have
  1854. * been rendered or displayed. So sadly enough, I'm changing it back to
  1855. * WWW_HTML, and it will handle the situation like Mosaic does, and as
  1856. * Robert Rowland suggested, because being functionally correct 99.9% of
  1857. * the time is better than being technically correct but functionally
  1858. * nonsensical. - FM
  1859. */
  1860. /***
  1861. me->format = WWW_UNKNOWN;
  1862. ***/
  1863. me->format = WWW_HTML;
  1864. me->targetRep = pres->rep_out;
  1865. me->boundary = NULL; /* Not set yet */
  1866. me->set_cookie = NULL; /* Not set yet */
  1867. me->set_cookie2 = NULL; /* Not set yet */
  1868. me->refresh_url = NULL; /* Not set yet */
  1869. me->encoding = 0; /* Not set yet */
  1870. me->compression_encoding = NULL; /* Not set yet */
  1871. me->net_ascii = NO; /* Local character set */
  1872. HTAnchor_setUCInfoStage(me->anchor, current_char_set,
  1873. UCT_STAGE_STRUCTURED,
  1874. UCT_SETBY_DEFAULT);
  1875. HTAnchor_setUCInfoStage(me->anchor, current_char_set,
  1876. UCT_STAGE_HTEXT,
  1877. UCT_SETBY_DEFAULT);
  1878. return me;
  1879. }
  1880. HTStream *HTNetMIME(HTPresentation *pres,
  1881. HTParentAnchor *anchor,
  1882. HTStream *sink)
  1883. {
  1884. HTStream *me = HTMIMEConvert(pres, anchor, sink);
  1885. if (!me)
  1886. return NULL;
  1887. me->net_ascii = YES;
  1888. return me;
  1889. }
  1890. HTStream *HTMIMERedirect(HTPresentation *pres,
  1891. HTParentAnchor *anchor,
  1892. HTStream *sink)
  1893. {
  1894. HTStream *me = HTMIMEConvert(pres, anchor, sink);
  1895. if (!me)
  1896. return NULL;
  1897. me->pickup_redirection = YES;
  1898. if (me->targetRep == WWW_DEBUG && sink)
  1899. me->no_streamstack = YES;
  1900. return me;
  1901. }
  1902. /* Japanese header handling functions
  1903. * ==================================
  1904. *
  1905. * K&Rized and added 07-Jun-96 by FM, based on:
  1906. *
  1907. ////////////////////////////////////////////////////////////////////////
  1908. *
  1909. * ISO-2022-JP handling routines
  1910. * &
  1911. * MIME decode routines (quick hack just for ISO-2022-JP)
  1912. *
  1913. * Thu Jan 25 10:11:42 JST 1996
  1914. *
  1915. * Copyright (C) 1994, 1995, 1996
  1916. * Shuichi Ichikawa (ichikawa@nuee.nagoya-u.ac.jp)
  1917. *
  1918. * This program is free software; you can redistribute it and/or modify
  1919. * it under the terms of the GNU General Public License as published by
  1920. * the Free Software Foundation; either versions 2, or (at your option)
  1921. * any later version.
  1922. *
  1923. * This program is distributed in the hope that it will be useful
  1924. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  1925. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1926. * GNU General Public License for more details.
  1927. *
  1928. * You should have received a copy of the GNU General Public License
  1929. * along with SKK, see the file COPYING. If not, write to the Free
  1930. * Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1931. */
  1932. /*
  1933. * MIME decoding routines
  1934. *
  1935. * Written by S. Ichikawa,
  1936. * partially inspired by encdec.c of <jh@efd.lth.se>.
  1937. * Caller's buffers decode to no longer than the input strings.
  1938. */
  1939. #include <LYCharVals.h> /* S/390 -- gil -- 0163 */
  1940. static char HTmm64[] =
  1941. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  1942. static char HTmmquote[] = "0123456789ABCDEF";
  1943. static int HTmmcont = 0;
  1944. static void HTmmdec_base64(char **t,
  1945. char *s)
  1946. {
  1947. int d, count, j, val;
  1948. char *buf, *bp, nw[4], *p;
  1949. if ((buf = malloc(strlen(s) * 3 + 1)) == 0)
  1950. outofmem(__FILE__, "HTmmdec_base64");
  1951. for (bp = buf; *s; s += 4) {
  1952. val = 0;
  1953. if (s[2] == '=')
  1954. count = 1;
  1955. else if (s[3] == '=')
  1956. count = 2;
  1957. else
  1958. count = 3;
  1959. for (j = 0; j <= count; j++) {
  1960. if (!(p = strchr(HTmm64, s[j]))) {
  1961. return;
  1962. }
  1963. d = p - HTmm64;
  1964. d <<= (3 - j) * 6;
  1965. val += d;
  1966. }
  1967. for (j = 2; j >= 0; j--) {
  1968. nw[j] = (char) (val & 255);
  1969. val >>= 8;
  1970. }
  1971. if (count--)
  1972. *bp++ = nw[0];
  1973. if (count--)
  1974. *bp++ = nw[1];
  1975. if (count)
  1976. *bp++ = nw[2];
  1977. }
  1978. *bp = '\0';
  1979. StrAllocCopy(*t, buf);
  1980. FREE(buf);
  1981. }
  1982. static void HTmmdec_quote(char **t,
  1983. char *s)
  1984. {
  1985. char *buf, cval, *bp, *p;
  1986. if ((buf = malloc(strlen(s) + 1)) == 0)
  1987. outofmem(__FILE__, "HTmmdec_quote");
  1988. for (bp = buf; *s;) {
  1989. if (*s == '=') {
  1990. cval = 0;
  1991. if (s[1] && (p = strchr(HTmmquote, s[1]))) {
  1992. cval += (char) (p - HTmmquote);
  1993. } else {
  1994. *bp++ = *s++;
  1995. continue;
  1996. }
  1997. if (s[2] && (p = strchr(HTmmquote, s[2]))) {
  1998. cval <<= 4;
  1999. cval += (char) (p - HTmmquote);
  2000. *bp++ = cval;
  2001. s += 3;
  2002. } else {
  2003. *bp++ = *s++;
  2004. }
  2005. } else if (*s == '_') {
  2006. *bp++ = 0x20;
  2007. s++;
  2008. } else {
  2009. *bp++ = *s++;
  2010. }
  2011. }
  2012. *bp = '\0';
  2013. StrAllocCopy(*t, buf);
  2014. FREE(buf);
  2015. }
  2016. /*
  2017. * HTmmdecode for ISO-2022-JP - FM
  2018. */
  2019. void HTmmdecode(char **target,
  2020. char *source)
  2021. {
  2022. char *buf;
  2023. char *mmbuf = NULL;
  2024. char *m2buf = NULL;
  2025. char *s, *t, *u;
  2026. int base64, quote;
  2027. if ((buf = malloc(strlen(source) + 1)) == 0)
  2028. outofmem(__FILE__, "HTmmdecode");
  2029. for (s = source, u = buf; *s;) {
  2030. if (!strncasecomp(s, "=?ISO-2022-JP?B?", 16)) {
  2031. base64 = 1;
  2032. } else {
  2033. base64 = 0;
  2034. }
  2035. if (!strncasecomp(s, "=?ISO-2022-JP?Q?", 16)) {
  2036. quote = 1;
  2037. } else {
  2038. quote = 0;
  2039. }
  2040. if (base64 || quote) {
  2041. if (HTmmcont) {
  2042. for (t = s - 1;
  2043. t >= source && (*t == ' ' || *t == '\t'); t--) {
  2044. u--;
  2045. }
  2046. }
  2047. if (mmbuf == 0) /* allocate buffer big enough for source */
  2048. StrAllocCopy(mmbuf, source);
  2049. for (s += 16, t = mmbuf; *s;) {
  2050. if (s[0] == '?' && s[1] == '=') {
  2051. break;
  2052. } else {
  2053. *t++ = *s++;
  2054. *t = '\0';
  2055. }
  2056. }
  2057. if (s[0] != '?' || s[1] != '=') {
  2058. goto end;
  2059. } else {
  2060. s += 2;
  2061. *t = '\0';
  2062. }
  2063. if (base64)
  2064. HTmmdec_base64(&m2buf, mmbuf);
  2065. if (quote)
  2066. HTmmdec_quote(&m2buf, mmbuf);
  2067. for (t = m2buf; *t;)
  2068. *u++ = *t++;
  2069. HTmmcont = 1;
  2070. } else {
  2071. if (*s != ' ' && *s != '\t')
  2072. HTmmcont = 0;
  2073. *u++ = *s++;
  2074. }
  2075. }
  2076. *u = '\0';
  2077. end:
  2078. StrAllocCopy(*target, buf);
  2079. FREE(m2buf);
  2080. FREE(mmbuf);
  2081. FREE(buf);
  2082. }
  2083. /*
  2084. * Insert ESC where it seems lost.
  2085. * (The author of this function "rjis" is S. Ichikawa.)
  2086. */
  2087. int HTrjis(char **t,
  2088. char *s)
  2089. {
  2090. char *p;
  2091. char *buf = NULL;
  2092. int kanji = 0;
  2093. if (strchr(s, CH_ESC) || !strchr(s, '$')) {
  2094. if (s != *t)
  2095. StrAllocCopy(*t, s);
  2096. return 1;
  2097. }
  2098. if ((buf = malloc(strlen(s) * 2 + 1)) == 0)
  2099. outofmem(__FILE__, "HTrjis");
  2100. for (p = buf; *s;) {
  2101. if (!kanji && s[0] == '$' && (s[1] == '@' || s[1] == 'B')) {
  2102. if (HTmaybekanji((int) s[2], (int) s[3])) {
  2103. kanji = 1;
  2104. *p++ = CH_ESC;
  2105. *p++ = *s++;
  2106. *p++ = *s++;
  2107. *p++ = *s++;
  2108. *p++ = *s++;
  2109. continue;
  2110. }
  2111. *p++ = *s++;
  2112. continue;
  2113. }
  2114. if (kanji && s[0] == '(' && (s[1] == 'J' || s[1] == 'B')) {
  2115. kanji = 0;
  2116. *p++ = CH_ESC;
  2117. *p++ = *s++;
  2118. *p++ = *s++;
  2119. continue;
  2120. }
  2121. *p++ = *s++;
  2122. }
  2123. *p = *s; /* terminate string */
  2124. StrAllocCopy(*t, buf);
  2125. FREE(buf);
  2126. return 0;
  2127. }
  2128. /*
  2129. * The following function "maybekanji" is derived from
  2130. * RJIS-1.0 by Mr. Hironobu Takahashi.
  2131. * Maybekanji() is included here under the courtesy of the author.
  2132. * The original comment of rjis.c is also included here.
  2133. */
  2134. /*
  2135. * RJIS ( Recover JIS code from broken file )
  2136. * $Header: rjis.c,v 0.2 92/09/04 takahasi Exp $
  2137. * Copyright (C) 1992 1994
  2138. * Hironobu Takahashi (takahasi@tiny.or.jp)
  2139. *
  2140. * This program is free software; you can redistribute it and/or modify
  2141. * it under the terms of the GNU General Public License as published by
  2142. * the Free Software Foundation; either versions 2, or (at your option)
  2143. * any later version.
  2144. *
  2145. * This program is distributed in the hope that it will be useful
  2146. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  2147. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2148. * GNU General Public License for more details.
  2149. *
  2150. * You should have received a copy of the GNU General Public License
  2151. * along with SKK, see the file COPYING. If not, write to the Free
  2152. * Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  2153. */
  2154. int HTmaybekanji(int c1,
  2155. int c2)
  2156. {
  2157. if ((c2 < 33) || (c2 > 126))
  2158. return 0;
  2159. if ((c1 < 33) || ((40 < c1) && (c1 < 48)) || (116 < c1))
  2160. return 0;
  2161. c2 -= 32;
  2162. switch (c1 - 32) {
  2163. case 2:
  2164. if ((14 < c2) && (c2 < 26))
  2165. return 0;
  2166. if ((33 < c2) && (c2 < 42))
  2167. return 0;
  2168. if ((48 < c2) && (c2 < 60))
  2169. return 0;
  2170. if ((74 < c2) && (c2 < 82))
  2171. return 0;
  2172. if ((89 < c2) && (c2 < 94))
  2173. return 0;
  2174. break;
  2175. case 3:
  2176. if (c2 < 16)
  2177. return 0;
  2178. if ((25 < c2) && (c2 < 33))
  2179. return 0;
  2180. if ((58 < c2) && (c2 < 65))
  2181. return 0;
  2182. if (90 < c2)
  2183. return 0;
  2184. break;
  2185. case 4:
  2186. if (83 < c2)
  2187. return 0;
  2188. break;
  2189. case 5:
  2190. if (86 < c2)
  2191. return 0;
  2192. break;
  2193. case 6:
  2194. if ((24 < c2) && (c2 < 33))
  2195. return 0;
  2196. if (56 < c2)
  2197. return 0;
  2198. break;
  2199. case 7:
  2200. if ((33 < c2) && (c2 < 49))
  2201. return 0;
  2202. if (81 < c2)
  2203. return 0;
  2204. break;
  2205. case 8:
  2206. if (32 < c2)
  2207. return 0;
  2208. break;
  2209. case 47:
  2210. if (51 < c2)
  2211. return 0;
  2212. break;
  2213. case 84:
  2214. if (6 < c2)
  2215. return 0;
  2216. break;
  2217. }
  2218. return 1;
  2219. }