HTTP.c 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293
  1. /* HyperText Tranfer Protocol - Client implementation HTTP.c
  2. * ==========================
  3. * Modified:
  4. * 27 Jan 1994 PDM Added Ari Luotonen's Fix for Reload when using proxy
  5. * servers.
  6. * 28 Apr 1997 AJL,FM Do Proxy Authorisation.
  7. */
  8. #include <HTUtils.h>
  9. #include <HTTP.h>
  10. #include <LYUtils.h>
  11. #ifdef USE_SSL
  12. #include <HTNews.h>
  13. #endif
  14. #define HTTP_VERSION "HTTP/1.0"
  15. #define HTTP_PORT 80
  16. #define HTTPS_PORT 443
  17. #define SNEWS_PORT 563
  18. #define INIT_LINE_SIZE 1536 /* Start with line buffer this big */
  19. #define LINE_EXTEND_THRESH 256 /* Minimum read size */
  20. #define VERSION_LENGTH 20 /* for returned protocol version */
  21. #include <HTParse.h>
  22. #include <HTTCP.h>
  23. #include <HTFormat.h>
  24. #include <HTFile.h>
  25. #include <HTAlert.h>
  26. #include <HTMIME.h>
  27. #include <HTML.h>
  28. #include <HTInit.h>
  29. #include <HTAABrow.h>
  30. #include <HTAccess.h> /* Are we using an HTTP gateway? */
  31. #include <LYCookie.h>
  32. #include <LYGlobalDefs.h>
  33. #include <GridText.h>
  34. #include <LYStrings.h>
  35. #include <LYrcFile.h>
  36. #include <LYLeaks.h>
  37. struct _HTStream {
  38. HTStreamClass *isa;
  39. };
  40. BOOL reloading = FALSE; /* Reloading => send no-cache pragma to proxy */
  41. char *redirecting_url = NULL; /* Location: value. */
  42. BOOL permanent_redirection = FALSE; /* Got 301 status? */
  43. BOOL redirect_post_content = FALSE; /* Don't convert to GET? */
  44. #ifdef USE_SSL
  45. SSL_CTX *ssl_ctx = NULL; /* SSL ctx */
  46. SSL *SSL_handle = NULL;
  47. static int ssl_okay;
  48. static void free_ssl_ctx(void)
  49. {
  50. if (ssl_ctx != NULL)
  51. SSL_CTX_free(ssl_ctx);
  52. }
  53. static int HTSSLCallback(int preverify_ok, X509_STORE_CTX * x509_ctx GCC_UNUSED)
  54. {
  55. char *msg = NULL;
  56. int result = 1;
  57. if (!(preverify_ok || ssl_okay || ssl_noprompt)) {
  58. #ifdef USE_X509_SUPPORT
  59. HTSprintf0(&msg, SSL_FORCED_PROMPT,
  60. X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
  61. if (HTForcedPrompt(ssl_noprompt, msg, YES))
  62. ssl_okay = 1;
  63. else
  64. result = 0;
  65. #endif
  66. FREE(msg);
  67. }
  68. return result;
  69. }
  70. SSL *HTGetSSLHandle(void)
  71. {
  72. #ifdef USE_GNUTLS_INCL
  73. static char *certfile = NULL;
  74. #endif
  75. if (ssl_ctx == NULL) {
  76. /*
  77. * First time only.
  78. */
  79. #if SSLEAY_VERSION_NUMBER < 0x0800
  80. ssl_ctx = SSL_CTX_new();
  81. X509_set_default_verify_paths(ssl_ctx->cert);
  82. #else
  83. SSLeay_add_ssl_algorithms();
  84. ssl_ctx = SSL_CTX_new(SSLv23_client_method());
  85. SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
  86. SSL_CTX_set_default_verify_paths(ssl_ctx);
  87. SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, HTSSLCallback);
  88. #endif /* SSLEAY_VERSION_NUMBER < 0x0800 */
  89. #ifdef USE_GNUTLS_INCL
  90. if ((certfile = LYGetEnv("SSL_CERT_FILE")) != NULL) {
  91. CTRACE((tfp,
  92. "HTGetSSLHandle: certfile is set to %s by SSL_CERT_FILE\n",
  93. certfile));
  94. }
  95. #endif
  96. atexit(free_ssl_ctx);
  97. }
  98. #ifdef USE_GNUTLS_INCL
  99. ssl_ctx->certfile = certfile;
  100. ssl_ctx->certfile_type = GNUTLS_X509_FMT_PEM;
  101. #endif
  102. ssl_okay = 0;
  103. return (SSL_new(ssl_ctx));
  104. }
  105. void HTSSLInitPRNG(void)
  106. {
  107. #if SSLEAY_VERSION_NUMBER >= 0x00905100
  108. if (RAND_status() == 0) {
  109. char rand_file[256];
  110. time_t t;
  111. int pid;
  112. long l, seed;
  113. t = time(NULL);
  114. pid = getpid();
  115. RAND_file_name(rand_file, 256);
  116. CTRACE((tfp, "HTTP: Seeding PRNG\n"));
  117. if (rand_file != NULL) {
  118. /* Seed as much as 1024 bytes from RAND_file_name */
  119. RAND_load_file(rand_file, 1024);
  120. }
  121. /* Seed in time (mod_ssl does this) */
  122. RAND_seed((unsigned char *) &t, sizeof(time_t));
  123. /* Seed in pid (mod_ssl does this) */
  124. RAND_seed((unsigned char *) &pid, sizeof(pid));
  125. /* Initialize system's random number generator */
  126. RAND_bytes((unsigned char *) &seed, sizeof(long));
  127. lynx_srand(seed);
  128. while (RAND_status() == 0) {
  129. /* Repeatedly seed the PRNG using the system's random number generator until it has been seeded with enough data */
  130. l = lynx_rand();
  131. RAND_seed((unsigned char *) &l, sizeof(long));
  132. }
  133. if (rand_file != NULL) {
  134. /* Write a rand_file */
  135. RAND_write_file(rand_file);
  136. }
  137. }
  138. #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
  139. return;
  140. }
  141. #define HTTP_NETREAD(sock, buff, size, handle) \
  142. (handle ? SSL_read(handle, buff, size) : NETREAD(sock, buff, size))
  143. #define HTTP_NETWRITE(sock, buff, size, handle) \
  144. (handle ? SSL_write(handle, buff, size) : NETWRITE(sock, buff, size))
  145. #define HTTP_NETCLOSE(sock, handle) \
  146. { (void)NETCLOSE(sock); if (handle) SSL_free(handle); SSL_handle = handle = NULL; }
  147. #else
  148. #define HTTP_NETREAD(a, b, c, d) NETREAD(a, b, c)
  149. #define HTTP_NETWRITE(a, b, c, d) NETWRITE(a, b, c)
  150. #define HTTP_NETCLOSE(a, b) (void)NETCLOSE(a)
  151. #endif /* USE_SSL */
  152. #ifdef _WINDOWS /* 1997/11/06 (Thu) 13:00:08 */
  153. #define BOX_TITLE "Lynx " __FILE__
  154. #define BOX_FLAG (MB_ICONINFORMATION | MB_SETFOREGROUND)
  155. typedef struct {
  156. int fd;
  157. char *buf;
  158. int len;
  159. } recv_data_t;
  160. int ws_read_per_sec = 0;
  161. static int ws_errno = 0;
  162. static DWORD g_total_times = 0;
  163. static DWORD g_total_bytes = 0;
  164. char *str_speed(void)
  165. {
  166. static char buff[32];
  167. if (ws_read_per_sec > 1000)
  168. sprintf(buff, "%d.%03dkB", ws_read_per_sec / 1000,
  169. (ws_read_per_sec % 1000));
  170. else
  171. sprintf(buff, "%3d", ws_read_per_sec);
  172. return buff;
  173. }
  174. /* The same like read, but takes care of EINTR and uses select to
  175. timeout the stale connections. */
  176. static int ws_read(int fd, char *buf, int len)
  177. {
  178. int res;
  179. int retry = 3;
  180. do {
  181. res = recv(fd, buf, len, 0);
  182. if (WSAEWOULDBLOCK == WSAGetLastError()) {
  183. Sleep(100);
  184. if (retry-- > 0)
  185. continue;
  186. }
  187. } while (res == SOCKET_ERROR && SOCKET_ERRNO == EINTR);
  188. return res;
  189. }
  190. #define DWORD_ERR ((DWORD)-1)
  191. static DWORD __stdcall _thread_func(void *p)
  192. {
  193. DWORD result;
  194. int i, val;
  195. recv_data_t *q = (recv_data_t *) p;
  196. i = 0;
  197. i++;
  198. val = ws_read(q->fd, q->buf, q->len);
  199. if (val == SOCKET_ERROR) {
  200. ws_errno = WSAGetLastError();
  201. #if 0
  202. char buff[256];
  203. sprintf(buff, "Thread read: %d, error (%ld), fd = %d, len = %d",
  204. i, ws_errno, q->fd, q->len);
  205. MessageBox(NULL, buff, BOX_TITLE, BOX_FLAG);
  206. #endif
  207. result = DWORD_ERR;
  208. } else {
  209. result = val;
  210. }
  211. return result;
  212. }
  213. /* The same like read, but takes care of EINTR and uses select to
  214. timeout the stale connections. */
  215. int ws_netread(int fd, char *buf, int len)
  216. {
  217. int i;
  218. char buff[256];
  219. /* 1998/03/30 (Mon) 09:01:21 */
  220. HANDLE hThread;
  221. DWORD dwThreadID;
  222. DWORD exitcode = 0;
  223. DWORD ret_val = DWORD_ERR;
  224. DWORD val, process_time, now_TickCount, save_TickCount;
  225. static recv_data_t para;
  226. extern int win32_check_interrupt(void); /* LYUtil.c */
  227. extern int lynx_timeout; /* LYMain.c */
  228. extern CRITICAL_SECTION critSec_READ; /* LYMain.c */
  229. #define TICK 5
  230. #define STACK_SIZE 0x2000uL
  231. InitializeCriticalSection(&critSec_READ);
  232. para.fd = fd;
  233. para.buf = buf;
  234. para.len = len;
  235. ws_read_per_sec = 0;
  236. save_TickCount = GetTickCount();
  237. hThread = CreateThread(NULL, STACK_SIZE,
  238. _thread_func,
  239. (void *) &para, 0UL, &dwThreadID);
  240. if (hThread == 0) {
  241. HTInfoMsg("CreateThread Failed (read)");
  242. goto read_exit;
  243. }
  244. i = 0;
  245. while (1) {
  246. val = WaitForSingleObject(hThread, 1000 / TICK);
  247. i++;
  248. if (val == WAIT_FAILED) {
  249. HTInfoMsg("Wait Failed");
  250. ret_val = DWORD_ERR;
  251. break;
  252. } else if (val == WAIT_TIMEOUT) {
  253. i++;
  254. if (i / TICK > (AlertSecs + 2)) {
  255. sprintf(buff, "Read Waiting (%2d.%01d) for %d Bytes",
  256. i / TICK, (i % TICK) * 10 / TICK, len);
  257. SetConsoleTitle(buff);
  258. }
  259. if (win32_check_interrupt() || ((i / TICK) > lynx_timeout)) {
  260. if (CloseHandle(hThread) == FALSE) {
  261. HTInfoMsg("Thread terminate Failed");
  262. }
  263. WSASetLastError(ETIMEDOUT);
  264. ret_val = HT_INTERRUPTED;
  265. break;
  266. }
  267. } else if (val == WAIT_OBJECT_0) {
  268. if (GetExitCodeThread(hThread, &exitcode) == FALSE) {
  269. exitcode = DWORD_ERR;
  270. }
  271. if (CloseHandle(hThread) == FALSE) {
  272. HTInfoMsg("Thread terminate Failed");
  273. }
  274. now_TickCount = GetTickCount();
  275. if (now_TickCount >= save_TickCount)
  276. process_time = now_TickCount - save_TickCount;
  277. else
  278. process_time = now_TickCount + (0xffffffff - save_TickCount);
  279. if (process_time == 0)
  280. process_time = 1;
  281. g_total_times += process_time;
  282. /*
  283. * DWORD is unsigned, and could be an error code which is signed.
  284. */
  285. if ((long) exitcode > 0)
  286. g_total_bytes += exitcode;
  287. ws_read_per_sec = g_total_bytes;
  288. if (ws_read_per_sec > 2000000) {
  289. if (g_total_times > 1000)
  290. ws_read_per_sec /= (g_total_times / 1000);
  291. } else {
  292. ws_read_per_sec *= 1000;
  293. ws_read_per_sec /= g_total_times;
  294. }
  295. ret_val = exitcode;
  296. break;
  297. }
  298. } /* end while(1) */
  299. read_exit:
  300. LeaveCriticalSection(&critSec_READ);
  301. return ret_val;
  302. }
  303. #endif /* _WINDOWS */
  304. /*
  305. * Strip any username from the given string so we retain only the host.
  306. */
  307. static void strip_userid(char *host)
  308. {
  309. char *p1 = host;
  310. char *p2 = strchr(host, '@');
  311. char *fake;
  312. if (p2 != 0) {
  313. *p2++ = '\0';
  314. if ((fake = HTParse(host, "", PARSE_HOST)) != NULL) {
  315. char *msg = NULL;
  316. CTRACE((tfp, "parsed:%s\n", fake));
  317. HTSprintf0(&msg, gettext("Address contains a username: %s"), host);
  318. HTAlert(msg);
  319. FREE(msg);
  320. }
  321. while ((*p1++ = *p2++) != '\0') {
  322. ;
  323. }
  324. }
  325. }
  326. /*
  327. * Check if the user's options specified to use the given encoding. Normally
  328. * all encodings with compiled-in support are specified (encodingALL).
  329. */
  330. static BOOL acceptEncoding(int code)
  331. {
  332. BOOL result = FALSE;
  333. if ((code & LYAcceptEncoding) != 0) {
  334. const char *program = 0;
  335. switch (code) {
  336. case encodingGZIP:
  337. program = HTGetProgramPath(ppGZIP);
  338. break;
  339. case encodingDEFLATE:
  340. program = HTGetProgramPath(ppINFLATE);
  341. break;
  342. case encodingCOMPRESS:
  343. program = HTGetProgramPath(ppCOMPRESS);
  344. break;
  345. case encodingBZIP2:
  346. program = HTGetProgramPath(ppBZIP2);
  347. break;
  348. default:
  349. break;
  350. }
  351. /*
  352. * FIXME: if lynx did not rely upon external programs to decompress
  353. * files for external viewers, this check could be relaxed.
  354. */
  355. result = (program != 0);
  356. }
  357. return result;
  358. }
  359. /* Load Document from HTTP Server HTLoadHTTP()
  360. * ==============================
  361. *
  362. * Given a hypertext address, this routine loads a document.
  363. *
  364. *
  365. * On entry,
  366. * arg is the hypertext reference of the article to be loaded.
  367. *
  368. * On exit,
  369. * returns >=0 If no error, a good socket number
  370. * <0 Error.
  371. *
  372. * The socket must be closed by the caller after the document has been
  373. * read.
  374. *
  375. */
  376. static int HTLoadHTTP(const char *arg,
  377. HTParentAnchor *anAnchor,
  378. HTFormat format_out,
  379. HTStream *sink)
  380. {
  381. static char *empty = "";
  382. int s; /* Socket number for returned data */
  383. const char *url = arg; /* The URL which get_physical() returned */
  384. bstring *command = NULL; /* The whole command */
  385. char *eol; /* End of line if found */
  386. char *start_of_data; /* Start of body of reply */
  387. int status; /* tcp return */
  388. int bytes_already_read;
  389. char crlf[3]; /* A CR LF equivalent string */
  390. HTStream *target; /* Unconverted data */
  391. HTFormat format_in; /* Format arriving in the message */
  392. BOOL do_head = FALSE; /* Whether or not we should do a head */
  393. BOOL do_post = FALSE; /* ARE WE posting ? */
  394. const char *METHOD;
  395. BOOL had_header; /* Have we had at least one header? */
  396. char *line_buffer;
  397. char *line_kept_clean;
  398. int real_length_of_line = 0;
  399. BOOL extensions; /* Assume good HTTP server */
  400. char *linebuf = NULL;
  401. char temp[80];
  402. BOOL first_Accept = TRUE;
  403. BOOL show_401 = FALSE;
  404. BOOL show_407 = FALSE;
  405. BOOL auth_proxy = NO; /* Generate a proxy authorization. - AJL */
  406. int length, rawlength, rv;
  407. int server_status;
  408. BOOL doing_redirect, already_retrying = FALSE;
  409. int len = 0;
  410. #ifdef USE_SSL
  411. BOOL do_connect = FALSE; /* ARE WE going to use a proxy tunnel ? */
  412. BOOL did_connect = FALSE; /* ARE WE actually using a proxy tunnel ? */
  413. const char *connect_url = NULL; /* The URL being proxied */
  414. char *connect_host = NULL; /* The host being proxied */
  415. SSL *handle = NULL; /* The SSL handle */
  416. char ssl_dn[1024];
  417. char *cert_host;
  418. char *ssl_host;
  419. char *p;
  420. char *msg = NULL;
  421. int status_sslcertcheck;
  422. char *ssl_dn_start;
  423. char *ssl_all_cns;
  424. #ifdef USE_GNUTLS_INCL
  425. int ret;
  426. unsigned tls_status;
  427. #endif
  428. #if SSLEAY_VERSION_NUMBER >= 0x0900
  429. BOOL try_tls = TRUE;
  430. #endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
  431. SSL_handle = NULL;
  432. #else
  433. void *handle = NULL;
  434. #endif /* USE_SSL */
  435. if (anAnchor->isHEAD)
  436. do_head = TRUE;
  437. else if (anAnchor->post_data)
  438. do_post = TRUE;
  439. if (!url) {
  440. status = -3;
  441. _HTProgress(BAD_REQUEST);
  442. goto done;
  443. }
  444. if (!*url) {
  445. status = -2;
  446. _HTProgress(BAD_REQUEST);
  447. goto done;
  448. }
  449. #ifdef USE_SSL
  450. if (using_proxy && !strncmp(url, "http://", 7)) {
  451. if ((connect_url = strstr((url + 7), "https://"))) {
  452. do_connect = TRUE;
  453. connect_host = HTParse(connect_url, "https", PARSE_HOST);
  454. if (!strchr(connect_host, ':')) {
  455. sprintf(temp, ":%d", HTTPS_PORT);
  456. StrAllocCat(connect_host, temp);
  457. }
  458. CTRACE((tfp, "HTTP: connect_url = '%s'\n", connect_url));
  459. CTRACE((tfp, "HTTP: connect_host = '%s'\n", connect_host));
  460. } else if ((connect_url = strstr((url + 7), "snews://"))) {
  461. do_connect = TRUE;
  462. connect_host = HTParse(connect_url, "snews", PARSE_HOST);
  463. if (!strchr(connect_host, ':')) {
  464. sprintf(temp, ":%d", SNEWS_PORT);
  465. StrAllocCat(connect_host, temp);
  466. }
  467. CTRACE((tfp, "HTTP: connect_url = '%s'\n", connect_url));
  468. CTRACE((tfp, "HTTP: connect_host = '%s'\n", connect_host));
  469. }
  470. }
  471. #endif /* USE_SSL */
  472. sprintf(crlf, "%c%c", CR, LF);
  473. /*
  474. * At this point, we're talking HTTP/1.0.
  475. */
  476. extensions = YES;
  477. try_again:
  478. /*
  479. * All initializations are moved down here from up above, so we can start
  480. * over here...
  481. */
  482. eol = 0;
  483. had_header = NO;
  484. length = 0;
  485. doing_redirect = FALSE;
  486. permanent_redirection = FALSE;
  487. redirect_post_content = FALSE;
  488. target = NULL;
  489. line_buffer = NULL;
  490. line_kept_clean = NULL;
  491. #ifdef USE_SSL
  492. if (!strncmp(url, "https", 5))
  493. status = HTDoConnect(url, "HTTPS", HTTPS_PORT, &s);
  494. else
  495. status = HTDoConnect(url, "HTTP", HTTP_PORT, &s);
  496. #else
  497. if (!strncmp(url, "https", 5)) {
  498. HTAlert(gettext("This client does not contain support for HTTPS URLs."));
  499. status = HT_NOT_LOADED;
  500. goto done;
  501. }
  502. status = HTDoConnect(arg, "HTTP", HTTP_PORT, &s);
  503. #endif /* USE_SSL */
  504. if (status == HT_INTERRUPTED) {
  505. /*
  506. * Interrupt cleanly.
  507. */
  508. CTRACE((tfp, "HTTP: Interrupted on connect; recovering cleanly.\n"));
  509. _HTProgress(CONNECTION_INTERRUPTED);
  510. status = HT_NOT_LOADED;
  511. goto done;
  512. }
  513. if (status < 0) {
  514. #ifdef _WINDOWS
  515. CTRACE((tfp, "HTTP: Unable to connect to remote host for `%s'\n"
  516. " (status = %d, sock_errno = %d).\n",
  517. url, status, SOCKET_ERRNO));
  518. #else
  519. CTRACE((tfp,
  520. "HTTP: Unable to connect to remote host for `%s' (errno = %d).\n",
  521. url, SOCKET_ERRNO));
  522. #endif
  523. HTAlert(gettext("Unable to connect to remote host."));
  524. status = HT_NOT_LOADED;
  525. goto done;
  526. }
  527. #ifdef USE_SSL
  528. use_tunnel:
  529. /*
  530. * If this is an https document, then do the SSL stuff here.
  531. */
  532. if (did_connect || !strncmp(url, "https", 5)) {
  533. SSL_handle = handle = HTGetSSLHandle();
  534. SSL_set_fd(handle, s);
  535. #if SSLEAY_VERSION_NUMBER >= 0x0900
  536. if (!try_tls)
  537. handle->options |= SSL_OP_NO_TLSv1;
  538. #endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
  539. HTSSLInitPRNG();
  540. status = SSL_connect(handle);
  541. if (status <= 0) {
  542. #if SSLEAY_VERSION_NUMBER >= 0x0900
  543. if (try_tls) {
  544. _HTProgress(gettext("Retrying connection without TLS."));
  545. try_tls = FALSE;
  546. if (did_connect)
  547. HTTP_NETCLOSE(s, handle);
  548. goto try_again;
  549. } else {
  550. unsigned long SSLerror;
  551. CTRACE((tfp,
  552. "HTTP: Unable to complete SSL handshake for '%s', SSL_connect=%d, SSL error stack dump follows\n",
  553. url, status));
  554. SSL_load_error_strings();
  555. while ((SSLerror = ERR_get_error()) != 0) {
  556. CTRACE((tfp, "HTTP: SSL: %s\n", ERR_error_string(SSLerror, NULL)));
  557. }
  558. HTAlert("Unable to make secure connection to remote host.");
  559. if (did_connect)
  560. HTTP_NETCLOSE(s, handle);
  561. status = HT_NOT_LOADED;
  562. goto done;
  563. }
  564. #else
  565. unsigned long SSLerror;
  566. CTRACE((tfp,
  567. "HTTP: Unable to complete SSL handshake for '%s', SSL_connect=%d, SSL error stack dump follows\n",
  568. url, status));
  569. SSL_load_error_strings();
  570. while ((SSLerror = ERR_get_error()) != 0) {
  571. CTRACE((tfp, "HTTP: SSL: %s\n", ERR_error_string(SSLerror, NULL)));
  572. }
  573. HTAlert("Unable to make secure connection to remote host.");
  574. if (did_connect)
  575. HTTP_NETCLOSE(s, handle);
  576. status = HT_NOT_LOADED;
  577. goto done;
  578. #endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
  579. }
  580. #ifdef USE_GNUTLS_INCL
  581. ret = gnutls_certificate_verify_peers2(handle->gnutls_state, &tls_status);
  582. if ((ret < 0) || tls_status) {
  583. int flag_continue = 1;
  584. char *msg2;
  585. if (tls_status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
  586. msg2 = gettext("no issuer was found");
  587. } else if (tls_status & GNUTLS_CERT_SIGNER_NOT_CA) {
  588. msg2 = gettext("issuer is not a CA");
  589. } else if (tls_status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
  590. msg2 = gettext("the certificate has no known issuer");
  591. } else if (tls_status & GNUTLS_CERT_REVOKED) {
  592. msg2 = gettext("the certificate has been revoked");
  593. } else {
  594. msg2 = gettext("the certificate is not trusted");
  595. }
  596. HTSprintf0(&msg, SSL_FORCED_PROMPT, msg2);
  597. CTRACE((tfp, "HTLoadHTTP: %s\n", msg));
  598. if (!ssl_noprompt) {
  599. if (!HTForcedPrompt(ssl_noprompt, msg, YES)) {
  600. flag_continue = 0;
  601. }
  602. } else if (ssl_noprompt == FORCE_PROMPT_NO) {
  603. flag_continue = 0;
  604. }
  605. FREE(msg);
  606. if (flag_continue == 0) {
  607. status = HT_NOT_LOADED;
  608. FREE(msg);
  609. goto done;
  610. }
  611. }
  612. #endif
  613. X509_NAME_oneline(X509_get_subject_name(SSL_get_peer_certificate(handle)),
  614. #ifndef USE_GNUTLS_INCL
  615. ssl_dn, sizeof(ssl_dn));
  616. #else
  617. ssl_dn + 1, sizeof(ssl_dn) - 1);
  618. /* Iterate over DN in incompatible GnuTLS format to bring it into OpenSSL format */
  619. ssl_dn[0] = '/';
  620. ssl_dn_start = ssl_dn;
  621. while (*ssl_dn_start) {
  622. if ((*ssl_dn_start == ',') && (*(ssl_dn_start + 1) == ' ')) {
  623. *ssl_dn_start++ = '/';
  624. if (*(p = ssl_dn_start) != 0) {
  625. while ((p[0] = p[1]) != 0)
  626. ++p;
  627. }
  628. } else {
  629. ssl_dn_start++;
  630. }
  631. }
  632. #endif
  633. /*
  634. * X.509 DN validation taking ALL CN fields into account
  635. * (c) 2006 Thorsten Glaser <tg@mirbsd.de>
  636. */
  637. /* initialise status information */
  638. status_sslcertcheck = 0; /* 0 = no CN found in DN */
  639. ssl_dn_start = ssl_dn;
  640. ssl_all_cns = NULL;
  641. /* get host we're connecting to */
  642. ssl_host = HTParse(url, "", PARSE_HOST);
  643. /* strip port number */
  644. if ((p = strchr(ssl_host, ':')) != NULL)
  645. *p = '\0';
  646. /* validate all CNs found in DN */
  647. while ((cert_host = strstr(ssl_dn_start, "/CN=")) != NULL) {
  648. status_sslcertcheck = 1; /* 1 = could not verify CN */
  649. /* start of CommonName */
  650. cert_host += 4;
  651. /* find next part of DistinguishedName */
  652. if ((p = strchr(cert_host, '/')) != NULL) {
  653. *p = '\0';
  654. ssl_dn_start = p; /* yes this points to the NUL byte */
  655. } else
  656. ssl_dn_start = NULL;
  657. /* strip port number */
  658. if ((p = strchr(cert_host, ':')) != NULL)
  659. *p = '\0';
  660. /* verify this CN */
  661. if (!strcasecomp_asterisk(ssl_host, cert_host)) {
  662. status_sslcertcheck = 2; /* 2 = verified peer */
  663. /* I think this is cool to have in the logs --mirabilos */
  664. HTSprintf0(&msg,
  665. gettext("Verified connection to %s (cert=%s)"),
  666. ssl_host, cert_host);
  667. _HTProgress(msg);
  668. FREE(msg);
  669. /* no need to continue the verification loop */
  670. break;
  671. }
  672. /* add this CN to list of failed CNs */
  673. if (ssl_all_cns == NULL) {
  674. StrAllocCopy(ssl_all_cns, cert_host);
  675. } else {
  676. StrAllocCat(ssl_all_cns, ":");
  677. StrAllocCat(ssl_all_cns, cert_host);
  678. }
  679. /* if we cannot retry, don't try it */
  680. if (ssl_dn_start == NULL)
  681. break;
  682. /* now retry next CN found in DN */
  683. *ssl_dn_start = '/'; /* formerly NUL byte */
  684. }
  685. /* if an error occurred, format the appropriate message */
  686. if (status_sslcertcheck == 0) {
  687. HTSprintf0(&msg, SSL_FORCED_PROMPT,
  688. gettext("Can't find common name in certificate"));
  689. } else if (status_sslcertcheck == 1) {
  690. HTSprintf0(&msg,
  691. gettext("SSL error:host(%s)!=cert(%s)-Continue?"),
  692. ssl_host, ssl_all_cns);
  693. }
  694. /* if an error occurred, let the user decide how much he trusts */
  695. if (status_sslcertcheck < 2) {
  696. if (!HTForcedPrompt(ssl_noprompt, msg, YES)) {
  697. status = HT_NOT_LOADED;
  698. FREE(msg);
  699. FREE(ssl_all_cns);
  700. goto done;
  701. }
  702. }
  703. HTSprintf0(&msg,
  704. gettext("Secure %d-bit %s (%s) HTTP connection"),
  705. SSL_get_cipher_bits(handle, NULL),
  706. SSL_get_cipher_version(handle),
  707. SSL_get_cipher(handle));
  708. _HTProgress(msg);
  709. FREE(msg);
  710. }
  711. #endif /* USE_SSL */
  712. /* Ask that node for the document, omitting the host name & anchor
  713. */
  714. {
  715. char *p1 = (HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION));
  716. #ifdef USE_SSL
  717. if (do_connect) {
  718. METHOD = "CONNECT";
  719. BStrCopy0(command, "CONNECT ");
  720. } else
  721. #endif /* USE_SSL */
  722. if (do_post) {
  723. METHOD = "POST";
  724. BStrCopy0(command, "POST ");
  725. } else if (do_head) {
  726. METHOD = "HEAD";
  727. BStrCopy0(command, "HEAD ");
  728. } else {
  729. METHOD = "GET";
  730. BStrCopy0(command, "GET ");
  731. }
  732. /*
  733. * If we are using a proxy gateway don't copy in the first slash of
  734. * say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj so that just
  735. * gopher://.... is sent.
  736. */
  737. #ifdef USE_SSL
  738. if (using_proxy && !did_connect) {
  739. if (do_connect)
  740. BStrCat0(command, connect_host);
  741. else
  742. BStrCat0(command, p1 + 1);
  743. }
  744. #else
  745. if (using_proxy)
  746. BStrCat0(command, p1 + 1);
  747. #endif /* USE_SSL */
  748. else
  749. BStrCat0(command, p1);
  750. FREE(p1);
  751. }
  752. if (extensions) {
  753. BStrCat0(command, " ");
  754. BStrCat0(command, HTTP_VERSION);
  755. }
  756. BStrCat0(command, crlf); /* CR LF, as in rfc 977 */
  757. if (extensions) {
  758. int n, i;
  759. char *host = NULL;
  760. if ((host = HTParse(anAnchor->address, "", PARSE_HOST)) != NULL) {
  761. strip_userid(host);
  762. HTBprintf(&command, "Host: %s%c%c", host, CR, LF);
  763. FREE(host);
  764. }
  765. if (!HTPresentations)
  766. HTFormatInit();
  767. n = HTList_count(HTPresentations);
  768. first_Accept = TRUE;
  769. len = 0;
  770. for (i = 0; i < n; i++) {
  771. HTPresentation *pres =
  772. (HTPresentation *) HTList_objectAt(HTPresentations, i);
  773. if (pres->get_accept) {
  774. if (pres->quality < 1.0) {
  775. if (pres->maxbytes > 0) {
  776. sprintf(temp, ";q=%4.3f;mxb=%ld",
  777. pres->quality, pres->maxbytes);
  778. } else {
  779. sprintf(temp, ";q=%4.3f", pres->quality);
  780. }
  781. } else if (pres->maxbytes > 0) {
  782. sprintf(temp, ";mxb=%ld", pres->maxbytes);
  783. } else {
  784. temp[0] = '\0';
  785. }
  786. HTSprintf0(&linebuf, "%s%s%s",
  787. (first_Accept ?
  788. "Accept: " : ", "),
  789. HTAtom_name(pres->rep),
  790. temp);
  791. len += strlen(linebuf);
  792. if (len > 252 && !first_Accept) {
  793. BStrCat0(command, crlf);
  794. HTSprintf0(&linebuf, "Accept: %s%s",
  795. HTAtom_name(pres->rep),
  796. temp);
  797. len = strlen(linebuf);
  798. }
  799. BStrCat0(command, linebuf);
  800. first_Accept = FALSE;
  801. }
  802. }
  803. HTBprintf(&command, "%s*/*;q=0.01%c%c",
  804. (first_Accept ?
  805. "Accept: " : ", "), CR, LF);
  806. first_Accept = FALSE;
  807. len = 0;
  808. /*
  809. * FIXME: suppressing the "Accept-Encoding" in this case is done to
  810. * work around limitations of the presentation logic used for the
  811. * command-line "-base" option. The remote site may transmit the
  812. * document gzip'd, but the ensuing logic in HTSaveToFile() would see
  813. * the mime-type as gzip rather than text/html, and not prepend the
  814. * base URL. This is less efficient than accepting the compressed data
  815. * and uncompressing it, adding the base URL but is simpler than
  816. * augmenting the dump's presentation logic -TD
  817. */
  818. if (LYPrependBaseToSource && dump_output_immediately) {
  819. CTRACE((tfp,
  820. "omit Accept-Encoding to work-around interaction with -source\n"));
  821. } else {
  822. char *list = 0;
  823. int j, k;
  824. for (j = 1; j < encodingALL; j <<= 1) {
  825. if (acceptEncoding(j)) {
  826. for (k = 0; tbl_preferred_encoding[k].name != 0; ++k) {
  827. if (tbl_preferred_encoding[k].value == j) {
  828. if (list != 0)
  829. StrAllocCat(list, ", ");
  830. StrAllocCat(list, tbl_preferred_encoding[k].name);
  831. break;
  832. }
  833. }
  834. }
  835. }
  836. if (list != 0) {
  837. HTBprintf(&command, "Accept-Encoding: %s%c%c", list, CR, LF);
  838. free(list);
  839. }
  840. }
  841. if (language && *language) {
  842. HTBprintf(&command, "Accept-Language: %s%c%c", language, CR, LF);
  843. }
  844. if (pref_charset && *pref_charset) {
  845. BStrCat0(command, "Accept-Charset: ");
  846. StrAllocCopy(linebuf, pref_charset);
  847. if (linebuf[strlen(linebuf) - 1] == ',')
  848. linebuf[strlen(linebuf) - 1] = '\0';
  849. LYLowerCase(linebuf);
  850. if (strstr(linebuf, "iso-8859-1") == NULL)
  851. StrAllocCat(linebuf, ", iso-8859-1;q=0.01");
  852. if (strstr(linebuf, "us-ascii") == NULL)
  853. StrAllocCat(linebuf, ", us-ascii;q=0.01");
  854. BStrCat0(command, linebuf);
  855. HTBprintf(&command, "%c%c", CR, LF);
  856. }
  857. #if 0
  858. /*
  859. * Promote 300 (Multiple Choices) replies, if supported, over 406 (Not
  860. * Acceptable) replies. - FM
  861. *
  862. * This used to be done in versions 2.7 and 2.8*, but violates the
  863. * specs for transparent content negotiation and has the effect that
  864. * servers supporting those specs will send 300 (Multiple Choices)
  865. * instead of a normal response (e.g. 200 OK), since they will assume
  866. * that the client wants to make the choice. It is not clear whether
  867. * there are any servers or sites for which sending this header really
  868. * improves anything.
  869. *
  870. * If there ever is a need to send "Negotiate: trans" and really mean
  871. * it, we should send "Negotiate: trans,trans" or similar, since that
  872. * is semantically equivalent and some servers may ignore "Negotiate:
  873. * trans" as a special case when it comes from Lynx (to work around the
  874. * old faulty behavior). - kw
  875. *
  876. * References:
  877. * RFC 2295 (see also RFC 2296), and mail to lynx-dev and
  878. * new-httpd@apache.org from Koen Holtman, Jan 1999.
  879. */
  880. if (!do_post) {
  881. HTBprintf(&command, "Negotiate: trans%c%c", CR, LF);
  882. }
  883. #endif /* 0 */
  884. /*
  885. * When reloading give no-cache pragma to proxy server to make it
  886. * refresh its cache. -- Ari L. <luotonen@dxcern.cern.ch>
  887. *
  888. * Also send it as a Cache-Control header for HTTP/1.1. - FM
  889. */
  890. if (reloading) {
  891. HTBprintf(&command, "Pragma: no-cache%c%c", CR, LF);
  892. HTBprintf(&command, "Cache-Control: no-cache%c%c", CR, LF);
  893. }
  894. if (LYUserAgent && *LYUserAgent) {
  895. char *cp = LYSkipBlanks(LYUserAgent);
  896. /* Won't send it at all if all blank - kw */
  897. if (*cp != '\0')
  898. HTBprintf(&command, "User-Agent: %.*s%c%c",
  899. INIT_LINE_SIZE - 15, LYUserAgent, CR, LF);
  900. } else {
  901. HTBprintf(&command, "User-Agent: %s/%s libwww-FM/%s%c%c",
  902. HTAppName ? HTAppName : "unknown",
  903. HTAppVersion ? HTAppVersion : "0.0",
  904. HTLibraryVersion, CR, LF);
  905. }
  906. if (personal_mail_address && !LYNoFromHeader) {
  907. HTBprintf(&command, "From: %s%c%c", personal_mail_address, CR, LF);
  908. }
  909. if (!(LYUserSpecifiedURL ||
  910. LYNoRefererHeader || LYNoRefererForThis) &&
  911. strcmp(HTLoadedDocumentURL(), "")) {
  912. const char *cp = LYRequestReferer;
  913. if (!cp)
  914. cp = HTLoadedDocumentURL(); /* @@@ Try both? - kw */
  915. BStrCat0(command, "Referer: ");
  916. if (isLYNXIMGMAP(cp)) {
  917. char *pound = findPoundSelector(cp);
  918. int nn = (pound ? (int) (pound - cp) : (int) strlen(cp));
  919. HTSABCat(&command, cp + LEN_LYNXIMGMAP, nn);
  920. } else {
  921. BStrCat0(command, cp);
  922. }
  923. HTBprintf(&command, "%c%c", CR, LF);
  924. } {
  925. char *abspath;
  926. char *docname;
  927. char *hostname;
  928. char *colon;
  929. int portnumber;
  930. char *auth, *cookie = NULL;
  931. BOOL secure = (BOOL) (strncmp(anAnchor->address, "https", 5) ?
  932. FALSE : TRUE);
  933. abspath = HTParse(arg, "", PARSE_PATH | PARSE_PUNCTUATION);
  934. docname = HTParse(arg, "", PARSE_PATH);
  935. hostname = HTParse(arg, "", PARSE_HOST);
  936. if (hostname &&
  937. NULL != (colon = strchr(hostname, ':'))) {
  938. *(colon++) = '\0'; /* Chop off port number */
  939. portnumber = atoi(colon);
  940. } else if (!strncmp(arg, "https", 5)) {
  941. portnumber = HTTPS_PORT;
  942. } else {
  943. portnumber = HTTP_PORT;
  944. }
  945. /*
  946. * Add Authorization, Proxy-Authorization, and/or Cookie headers,
  947. * if applicable.
  948. */
  949. if (using_proxy) {
  950. /*
  951. * If we are using a proxy, first determine if we should
  952. * include an Authorization header and/or Cookie header for the
  953. * ultimate target of this request. - FM & AJL
  954. */
  955. char *host2 = NULL, *path2 = NULL;
  956. int port2 = (strncmp(docname, "https", 5) ?
  957. HTTP_PORT : HTTPS_PORT);
  958. host2 = HTParse(docname, "", PARSE_HOST);
  959. path2 = HTParse(docname, "", PARSE_PATH | PARSE_PUNCTUATION);
  960. if (host2) {
  961. if ((colon = strchr(host2, ':')) != NULL) {
  962. /* Use non-default port number */
  963. *colon = '\0';
  964. colon++;
  965. port2 = atoi(colon);
  966. }
  967. }
  968. /*
  969. * This composeAuth() does file access, i.e., for the ultimate
  970. * target of the request. - AJL
  971. */
  972. auth_proxy = NO;
  973. if ((auth = HTAA_composeAuth(host2, port2, path2,
  974. auth_proxy)) != NULL &&
  975. *auth != '\0') {
  976. /*
  977. * If auth is not NULL nor zero-length, it's an
  978. * Authorization header to be included. - FM
  979. */
  980. HTBprintf(&command, "%s%c%c", auth, CR, LF);
  981. CTRACE((tfp, "HTTP: Sending authorization: %s\n", auth));
  982. } else if (auth && *auth == '\0') {
  983. /*
  984. * If auth is a zero-length string, the user either
  985. * cancelled or goofed at the username and password prompt.
  986. * - FM
  987. */
  988. if (!(traversal || dump_output_immediately) &&
  989. HTConfirm(CONFIRM_WO_PASSWORD)) {
  990. show_401 = TRUE;
  991. } else {
  992. if (traversal || dump_output_immediately)
  993. HTAlert(FAILED_NEED_PASSWD);
  994. #ifdef USE_SSL
  995. if (did_connect)
  996. HTTP_NETCLOSE(s, handle);
  997. #endif /* USE_SSL */
  998. BStrFree(command);
  999. FREE(hostname);
  1000. FREE(docname);
  1001. FREE(abspath);
  1002. FREE(host2);
  1003. FREE(path2);
  1004. status = HT_NOT_LOADED;
  1005. goto done;
  1006. }
  1007. } else {
  1008. CTRACE((tfp, "HTTP: Not sending authorization (yet).\n"));
  1009. }
  1010. /*
  1011. * Add 'Cookie:' header, if it's HTTP or HTTPS document being
  1012. * proxied.
  1013. */
  1014. if (!strncmp(docname, "http", 4)) {
  1015. cookie = LYAddCookieHeader(host2, path2, port2, secure);
  1016. }
  1017. FREE(host2);
  1018. FREE(path2);
  1019. /*
  1020. * The next composeAuth() will be for the proxy. - AJL
  1021. */
  1022. auth_proxy = YES;
  1023. } else {
  1024. /*
  1025. * Add cookie for a non-proxied request. - FM
  1026. */
  1027. cookie = LYAddCookieHeader(hostname, abspath, portnumber, secure);
  1028. auth_proxy = NO;
  1029. }
  1030. /*
  1031. * If we do have a cookie set, add it to the request buffer. - FM
  1032. */
  1033. if (cookie != NULL) {
  1034. if (*cookie != '$') {
  1035. /*
  1036. * It's a historical cookie, so signal to the server that
  1037. * we support modern cookies. - FM
  1038. */
  1039. BStrCat0(command, "Cookie2: $Version=\"1\"");
  1040. BStrCat0(command, crlf);
  1041. CTRACE((tfp, "HTTP: Sending Cookie2: $Version =\"1\"\n"));
  1042. }
  1043. if (*cookie != '\0') {
  1044. /*
  1045. * It's not a zero-length string, so add the header. Note
  1046. * that any folding of long strings has been done already
  1047. * in LYCookie.c. - FM
  1048. */
  1049. BStrCat0(command, "Cookie: ");
  1050. BStrCat0(command, cookie);
  1051. BStrCat0(command, crlf);
  1052. CTRACE((tfp, "HTTP: Sending Cookie: %s\n", cookie));
  1053. }
  1054. FREE(cookie);
  1055. }
  1056. FREE(abspath);
  1057. /*
  1058. * If we are using a proxy, auth_proxy should be YES, and we check
  1059. * here whether we want a Proxy-Authorization header for it. If we
  1060. * are not using a proxy, auth_proxy should still be NO, and we
  1061. * check here for whether we want an Authorization header. - FM &
  1062. * AJL
  1063. */
  1064. if ((auth = HTAA_composeAuth(hostname,
  1065. portnumber,
  1066. docname,
  1067. auth_proxy)) != NULL &&
  1068. *auth != '\0') {
  1069. /*
  1070. * If auth is not NULL nor zero-length, it's an Authorization
  1071. * or Proxy-Authorization header to be included. - FM
  1072. */
  1073. HTBprintf(&command, "%s%c%c", auth, CR, LF);
  1074. CTRACE((tfp, (auth_proxy ?
  1075. "HTTP: Sending proxy authorization: %s\n" :
  1076. "HTTP: Sending authorization: %s\n"),
  1077. auth));
  1078. } else if (auth && *auth == '\0') {
  1079. /*
  1080. * If auth is a zero-length string, the user either cancelled
  1081. * or goofed at the username and password prompt. - FM
  1082. */
  1083. if (!(traversal || dump_output_immediately) && HTConfirm(CONFIRM_WO_PASSWORD)) {
  1084. if (auth_proxy == TRUE) {
  1085. show_407 = TRUE;
  1086. } else {
  1087. show_401 = TRUE;
  1088. }
  1089. } else {
  1090. if (traversal || dump_output_immediately)
  1091. HTAlert(FAILED_NEED_PASSWD);
  1092. BStrFree(command);
  1093. FREE(hostname);
  1094. FREE(docname);
  1095. status = HT_NOT_LOADED;
  1096. goto done;
  1097. }
  1098. } else {
  1099. CTRACE((tfp, (auth_proxy ?
  1100. "HTTP: Not sending proxy authorization (yet).\n" :
  1101. "HTTP: Not sending authorization (yet).\n")));
  1102. }
  1103. FREE(hostname);
  1104. FREE(docname);
  1105. }
  1106. auth_proxy = NO;
  1107. }
  1108. if (
  1109. #ifdef USE_SSL
  1110. !do_connect &&
  1111. #endif /* USE_SSL */
  1112. do_post) {
  1113. CTRACE((tfp, "HTTP: Doing post, content-type '%s'\n",
  1114. anAnchor->post_content_type
  1115. ? anAnchor->post_content_type
  1116. : "lose"));
  1117. HTBprintf(&command, "Content-type: %s%c%c",
  1118. anAnchor->post_content_type
  1119. ? anAnchor->post_content_type
  1120. : "lose",
  1121. CR, LF);
  1122. HTBprintf(&command, "Content-length: %d%c%c",
  1123. !isBEmpty(anAnchor->post_data)
  1124. ? BStrLen(anAnchor->post_data)
  1125. : 0,
  1126. CR, LF);
  1127. BStrCat0(command, crlf); /* Blank line means "end" of headers */
  1128. BStrCat(command, anAnchor->post_data);
  1129. } else
  1130. BStrCat0(command, crlf); /* Blank line means "end" of headers */
  1131. if (TRACE) {
  1132. CTRACE((tfp, "Writing:\n"));
  1133. trace_bstring(command);
  1134. #ifdef USE_SSL
  1135. CTRACE((tfp, "%s",
  1136. (anAnchor->post_data && !do_connect ? crlf : "")));
  1137. #else
  1138. CTRACE((tfp, "%s",
  1139. (anAnchor->post_data ? crlf : "")));
  1140. #endif /* USE_SSL */
  1141. CTRACE((tfp, "----------------------------------\n"));
  1142. }
  1143. _HTProgress(gettext("Sending HTTP request."));
  1144. #ifdef NOT_ASCII /* S/390 -- gil -- 0548 */
  1145. {
  1146. char *p2;
  1147. for (p2 = BStrData(command);
  1148. p2 < BStrData(command) + BStrLen(command);
  1149. p2++)
  1150. *p2 = TOASCII(*p2);
  1151. }
  1152. #endif /* NOT_ASCII */
  1153. status = HTTP_NETWRITE(s, BStrData(command), BStrLen(command), handle);
  1154. BStrFree(command);
  1155. FREE(linebuf);
  1156. if (status <= 0) {
  1157. if (status == 0) {
  1158. CTRACE((tfp, "HTTP: Got status 0 in initial write\n"));
  1159. /* Do nothing. */
  1160. } else if ((SOCKET_ERRNO == ENOTCONN ||
  1161. SOCKET_ERRNO == ECONNRESET ||
  1162. SOCKET_ERRNO == EPIPE) &&
  1163. !already_retrying &&
  1164. /* Don't retry if we're posting. */ !do_post) {
  1165. /*
  1166. * Arrrrgh, HTTP 0/1 compatibility problem, maybe.
  1167. */
  1168. CTRACE((tfp,
  1169. "HTTP: BONZO ON WRITE Trying again with HTTP0 request.\n"));
  1170. _HTProgress(RETRYING_AS_HTTP0);
  1171. HTTP_NETCLOSE(s, handle);
  1172. extensions = NO;
  1173. already_retrying = TRUE;
  1174. goto try_again;
  1175. } else {
  1176. CTRACE((tfp,
  1177. "HTTP: Hit unexpected network WRITE error; aborting connection.\n"));
  1178. HTTP_NETCLOSE(s, handle);
  1179. status = -1;
  1180. HTAlert(gettext("Unexpected network write error; connection aborted."));
  1181. goto done;
  1182. }
  1183. }
  1184. CTRACE((tfp, "HTTP: WRITE delivered OK\n"));
  1185. _HTProgress(gettext("HTTP request sent; waiting for response."));
  1186. /* Read the first line of the response
  1187. * -----------------------------------
  1188. */
  1189. {
  1190. /* Get numeric status etc */
  1191. BOOL end_of_file = NO;
  1192. int buffer_length = INIT_LINE_SIZE;
  1193. line_buffer = typecallocn(char, buffer_length);
  1194. if (line_buffer == NULL)
  1195. outofmem(__FILE__, "HTLoadHTTP");
  1196. HTReadProgress(bytes_already_read = 0, 0);
  1197. do { /* Loop to read in the first line */
  1198. /*
  1199. * Extend line buffer if necessary for those crazy WAIS URLs ;-)
  1200. */
  1201. if (buffer_length - length < LINE_EXTEND_THRESH) {
  1202. buffer_length = buffer_length + buffer_length;
  1203. line_buffer =
  1204. (char *) realloc(line_buffer, (buffer_length * sizeof(char)));
  1205. if (line_buffer == NULL)
  1206. outofmem(__FILE__, "HTLoadHTTP");
  1207. }
  1208. CTRACE((tfp, "HTTP: Trying to read %d\n", buffer_length - length - 1));
  1209. status = HTTP_NETREAD(s, line_buffer + length,
  1210. buffer_length - length - 1, handle);
  1211. CTRACE((tfp, "HTTP: Read %d\n", status));
  1212. if (status <= 0) {
  1213. /*
  1214. * Retry if we get nothing back too.
  1215. * Bomb out if we get nothing twice.
  1216. */
  1217. if (status == HT_INTERRUPTED) {
  1218. CTRACE((tfp, "HTTP: Interrupted initial read.\n"));
  1219. _HTProgress(CONNECTION_INTERRUPTED);
  1220. HTTP_NETCLOSE(s, handle);
  1221. status = HT_NO_DATA;
  1222. goto clean_up;
  1223. } else if (status < 0 &&
  1224. (SOCKET_ERRNO == ENOTCONN ||
  1225. #ifdef _WINDOWS /* 1997/11/09 (Sun) 16:59:58 */
  1226. SOCKET_ERRNO == ETIMEDOUT ||
  1227. #endif
  1228. SOCKET_ERRNO == ECONNRESET ||
  1229. SOCKET_ERRNO == EPIPE) &&
  1230. !already_retrying && !do_post) {
  1231. /*
  1232. * Arrrrgh, HTTP 0/1 compability problem, maybe.
  1233. */
  1234. CTRACE((tfp,
  1235. "HTTP: BONZO Trying again with HTTP0 request.\n"));
  1236. HTTP_NETCLOSE(s, handle);
  1237. FREE(line_buffer);
  1238. FREE(line_kept_clean);
  1239. extensions = NO;
  1240. already_retrying = TRUE;
  1241. _HTProgress(RETRYING_AS_HTTP0);
  1242. goto try_again;
  1243. } else {
  1244. CTRACE((tfp,
  1245. "HTTP: Hit unexpected network read error; aborting connection; status %d.\n",
  1246. status));
  1247. HTAlert(gettext("Unexpected network read error; connection aborted."));
  1248. HTTP_NETCLOSE(s, handle);
  1249. status = -1;
  1250. goto clean_up;
  1251. }
  1252. }
  1253. #ifdef NOT_ASCII /* S/390 -- gil -- 0564 */
  1254. {
  1255. char *p2;
  1256. for (p2 = line_buffer + length;
  1257. p2 < line_buffer + length + status;
  1258. p2++)
  1259. *p2 = FROMASCII(*p2);
  1260. }
  1261. #endif /* NOT_ASCII */
  1262. bytes_already_read += status;
  1263. HTReadProgress(bytes_already_read, 0);
  1264. #ifdef UCX /* UCX returns -1 on EOF */
  1265. if (status == 0 || status == -1)
  1266. #else
  1267. if (status == 0)
  1268. #endif
  1269. {
  1270. end_of_file = YES;
  1271. break;
  1272. }
  1273. line_buffer[length + status] = 0;
  1274. if (line_buffer) {
  1275. FREE(line_kept_clean);
  1276. line_kept_clean = (char *) malloc(buffer_length * sizeof(char));
  1277. if (line_kept_clean == NULL)
  1278. outofmem(__FILE__, "HTLoadHTTP");
  1279. memcpy(line_kept_clean, line_buffer, buffer_length);
  1280. real_length_of_line = length + status;
  1281. }
  1282. eol = strchr(line_buffer + length, LF);
  1283. /* Do we *really* want to do this? */
  1284. if (eol && eol != line_buffer && *(eol - 1) == CR)
  1285. *(eol - 1) = ' ';
  1286. length = length + status;
  1287. /* Do we really want to do *this*? */
  1288. if (eol)
  1289. *eol = 0; /* Terminate the line */
  1290. }
  1291. /* All we need is the first line of the response. If it's a HTTP/1.0
  1292. * response, then the first line will be absurdly short and therefore
  1293. * we can safely gate the number of bytes read through this code (as
  1294. * opposed to below) to ~1000.
  1295. *
  1296. * Well, let's try 100.
  1297. */
  1298. while (!eol && !end_of_file && bytes_already_read < 100);
  1299. } /* Scope of loop variables */
  1300. /* save total length, in case we decide later to show it all - kw */
  1301. rawlength = length;
  1302. /* We now have a terminated unfolded line. Parse it.
  1303. * --------------------------------------------------
  1304. */
  1305. CTRACE((tfp, "HTTP: Rx: %s\n", line_buffer));
  1306. /*
  1307. * Kludge to work with old buggy servers and the VMS Help gateway. They
  1308. * can't handle the third word, so we try again without it.
  1309. */
  1310. if (extensions && /* Old buggy server or Help gateway? */
  1311. (0 == strncmp(line_buffer, "<TITLE>Bad File Request</TITLE>", 31) ||
  1312. 0 == strncmp(line_buffer, "Address should begin with", 25) ||
  1313. 0 == strncmp(line_buffer, "<TITLE>Help ", 12) ||
  1314. 0 == strcmp(line_buffer,
  1315. "Document address invalid or access not authorised"))) {
  1316. FREE(line_buffer);
  1317. FREE(line_kept_clean);
  1318. extensions = NO;
  1319. already_retrying = TRUE;
  1320. CTRACE((tfp, "HTTP: close socket %d to retry with HTTP0\n", s));
  1321. HTTP_NETCLOSE(s, handle);
  1322. /* print a progress message */
  1323. _HTProgress(RETRYING_AS_HTTP0);
  1324. goto try_again;
  1325. } {
  1326. int fields;
  1327. char server_version[VERSION_LENGTH + 1];
  1328. server_version[0] = 0;
  1329. fields = sscanf(line_buffer, "%20s %d",
  1330. server_version,
  1331. &server_status);
  1332. CTRACE((tfp, "HTTP: Scanned %d fields from line_buffer\n", fields));
  1333. if (http_error_file) { /* Make the status code externally available */
  1334. FILE *error_file;
  1335. #ifdef SERVER_STATUS_ONLY
  1336. error_file = fopen(http_error_file, TXT_W);
  1337. if (error_file) { /* Managed to open the file */
  1338. fprintf(error_file, "error=%d\n", server_status);
  1339. fclose(error_file);
  1340. }
  1341. #else
  1342. error_file = fopen(http_error_file, TXT_A);
  1343. if (error_file) { /* Managed to open the file */
  1344. fprintf(error_file, " URL=%s (%s)\n", url, METHOD);
  1345. fprintf(error_file, "STATUS=%s\n", line_buffer);
  1346. fclose(error_file);
  1347. }
  1348. #endif /* SERVER_STATUS_ONLY */
  1349. }
  1350. /*
  1351. * Rule out a non-HTTP/1.n reply as best we can.
  1352. */
  1353. if (fields < 2 || !server_version[0] || server_version[0] != 'H' ||
  1354. server_version[1] != 'T' || server_version[2] != 'T' ||
  1355. server_version[3] != 'P' || server_version[4] != '/' ||
  1356. server_version[6] != '.') {
  1357. /*
  1358. * Ugh! An HTTP0 reply,
  1359. */
  1360. HTAtom *encoding;
  1361. CTRACE((tfp, "--- Talking HTTP0.\n"));
  1362. format_in = HTFileFormat(url, &encoding, NULL);
  1363. /*
  1364. * Treat all plain text as HTML. This sucks but its the only
  1365. * solution without without looking at content.
  1366. */
  1367. if (!strncmp(HTAtom_name(format_in), "text/plain", 10)) {
  1368. CTRACE((tfp, "HTTP: format_in being changed to text/HTML\n"));
  1369. format_in = WWW_HTML;
  1370. }
  1371. if (!IsUnityEnc(encoding)) {
  1372. /*
  1373. * Change the format to that for "www/compressed".
  1374. */
  1375. CTRACE((tfp, "HTTP: format_in is '%s',\n", HTAtom_name(format_in)));
  1376. StrAllocCopy(anAnchor->content_type, HTAtom_name(format_in));
  1377. StrAllocCopy(anAnchor->content_encoding, HTAtom_name(encoding));
  1378. format_in = HTAtom_for("www/compressed");
  1379. CTRACE((tfp, " Treating as '%s' with encoding '%s'\n",
  1380. "www/compressed", HTAtom_name(encoding)));
  1381. }
  1382. start_of_data = line_kept_clean;
  1383. } else {
  1384. /*
  1385. * Set up to decode full HTTP/1.n response. - FM
  1386. */
  1387. format_in = HTAtom_for("www/mime");
  1388. CTRACE((tfp, "--- Talking HTTP1.\n"));
  1389. /*
  1390. * We set start_of_data to "" when !eol here because there will be
  1391. * a put_block done below; we do *not* use the value of
  1392. * start_of_data (as a pointer) in the computation of length (or
  1393. * anything else) when !eol. Otherwise, set the value of length to
  1394. * what we have beyond eol (i.e., beyond the status line). - FM
  1395. */
  1396. start_of_data = eol ? eol + 1 : empty;
  1397. length = eol ? length - (start_of_data - line_buffer) : 0;
  1398. /*
  1399. * Trim trailing spaces in line_buffer so that we can use it in
  1400. * messages which include the status line. - FM
  1401. */
  1402. while (line_buffer[strlen(line_buffer) - 1] == ' ')
  1403. line_buffer[strlen(line_buffer) - 1] = '\0';
  1404. /*
  1405. * Take appropriate actions based on the status. - FM
  1406. */
  1407. switch (server_status / 100) {
  1408. case 1:
  1409. /*
  1410. * HTTP/1.1 Informational statuses.
  1411. * 100 Continue.
  1412. * 101 Switching Protocols.
  1413. * > 101 is unknown.
  1414. * We should never get these, and they have only the status
  1415. * line and possibly other headers, so we'll deal with them by
  1416. * showing the full header to the user as text/plain. - FM
  1417. */
  1418. HTAlert(gettext("Got unexpected Informational Status."));
  1419. do_head = TRUE;
  1420. break;
  1421. case 2:
  1422. /*
  1423. * Good: Got MIME object! (Successful) - FM
  1424. */
  1425. if (do_head) {
  1426. /*
  1427. * If HEAD was requested, show headers (and possibly bogus
  1428. * body) for all 2xx status codes as text/plain - KW
  1429. */
  1430. HTProgress(line_buffer);
  1431. break;
  1432. }
  1433. switch (server_status) {
  1434. case 204:
  1435. /*
  1436. * No Content.
  1437. */
  1438. HTAlert(line_buffer);
  1439. HTTP_NETCLOSE(s, handle);
  1440. HTNoDataOK = 1;
  1441. status = HT_NO_DATA;
  1442. goto clean_up;
  1443. case 205:
  1444. /*
  1445. * Reset Content. The server has fulfilled the request but
  1446. * nothing is returned and we should reset any form
  1447. * content. We'll instruct the user to do that, and
  1448. * restore the current document. - FM
  1449. */
  1450. HTAlert(gettext("Request fulfilled. Reset Content."));
  1451. HTTP_NETCLOSE(s, handle);
  1452. status = HT_NO_DATA;
  1453. goto clean_up;
  1454. case 206:
  1455. /*
  1456. * Partial Content. We didn't send a Range so something
  1457. * went wrong somewhere. Show the status message and
  1458. * restore the current document. - FM
  1459. */
  1460. HTAlert(line_buffer);
  1461. HTTP_NETCLOSE(s, handle);
  1462. status = HT_NO_DATA;
  1463. goto clean_up;
  1464. default:
  1465. /*
  1466. * 200 OK.
  1467. * 201 Created.
  1468. * 202 Accepted.
  1469. * 203 Non-Authoritative Information.
  1470. * > 206 is unknown.
  1471. * All should return something to display.
  1472. */
  1473. #if defined(USE_SSL) && !defined(DISABLE_NEWS)
  1474. if (do_connect) {
  1475. CTRACE((tfp,
  1476. "HTTP: Proxy tunnel to '%s' established.\n",
  1477. connect_host));
  1478. do_connect = FALSE;
  1479. url = connect_url;
  1480. FREE(line_buffer);
  1481. FREE(line_kept_clean);
  1482. if (!strncmp(connect_url, "snews", 5)) {
  1483. CTRACE((tfp,
  1484. " Will attempt handshake and snews connection.\n"));
  1485. status = HTNewsProxyConnect(s, url, anAnchor,
  1486. format_out, sink);
  1487. goto done;
  1488. }
  1489. did_connect = TRUE;
  1490. already_retrying = TRUE;
  1491. eol = 0;
  1492. bytes_already_read = 0;
  1493. had_header = NO;
  1494. length = 0;
  1495. doing_redirect = FALSE;
  1496. permanent_redirection = FALSE;
  1497. target = NULL;
  1498. CTRACE((tfp,
  1499. " Will attempt handshake and resubmit headers.\n"));
  1500. goto use_tunnel;
  1501. }
  1502. #endif /* USE_SSL */
  1503. HTProgress(line_buffer);
  1504. } /* case 2 switch */
  1505. break;
  1506. case 3:
  1507. /*
  1508. * Various forms of Redirection. - FM
  1509. * 300 Multiple Choices.
  1510. * 301 Moved Permanently.
  1511. * 302 Found (temporary; we can, and do, use GET).
  1512. * 303 See Other (temporary; always use GET).
  1513. * 304 Not Modified.
  1514. * 305 Use Proxy.
  1515. * 306 Set Proxy.
  1516. * 307 Temporary Redirect with method retained.
  1517. * > 308 is unknown.
  1518. */
  1519. if (no_url_redirection || do_head || keep_mime_headers) {
  1520. /*
  1521. * If any of these flags are set, we do not redirect, but
  1522. * instead show what was returned to the user as
  1523. * text/plain. - FM
  1524. */
  1525. HTProgress(line_buffer);
  1526. break;
  1527. }
  1528. if (server_status == 300) { /* Multiple Choices */
  1529. /*
  1530. * For client driven content negotiation. The server
  1531. * should be sending some way for the user-agent to make a
  1532. * selection, so we'll show the user whatever the server
  1533. * returns. There might be a Location: header with the
  1534. * server's preference present, but the choice should be up
  1535. * to the user, someday based on an Alternates: header,
  1536. * and a body always should be present with descriptions
  1537. * and links for the choices (i.e., we use the latter, for
  1538. * now). - FM
  1539. */
  1540. HTAlert(line_buffer);
  1541. if (traversal) {
  1542. HTTP_NETCLOSE(s, handle);
  1543. status = -1;
  1544. goto clean_up;
  1545. }
  1546. if (!dump_output_immediately &&
  1547. format_out == HTAtom_for("www/download")) {
  1548. /*
  1549. * Convert a download request to a presentation request
  1550. * for interactive users. - FM
  1551. */
  1552. format_out = WWW_PRESENT;
  1553. }
  1554. break;
  1555. }
  1556. if (server_status == 304) { /* Not Modified */
  1557. /*
  1558. * We didn't send an "If-Modified-Since" header, so this
  1559. * status is inappropriate. We'll deal with it by showing
  1560. * the full header to the user as text/plain. - FM
  1561. */
  1562. HTAlert(gettext("Got unexpected 304 Not Modified status."));
  1563. do_head = TRUE;
  1564. break;
  1565. }
  1566. if (server_status == 305 ||
  1567. server_status == 306 ||
  1568. server_status > 307) {
  1569. /*
  1570. * Show user the content, if any, for 305, 306, or unknown
  1571. * status. - FM
  1572. */
  1573. HTAlert(line_buffer);
  1574. if (traversal) {
  1575. HTTP_NETCLOSE(s, handle);
  1576. status = -1;
  1577. goto clean_up;
  1578. }
  1579. if (!dump_output_immediately &&
  1580. format_out == HTAtom_for("www/download")) {
  1581. /*
  1582. * Convert a download request to a presentation request
  1583. * for interactive users. - FM
  1584. */
  1585. format_out = WWW_PRESENT;
  1586. }
  1587. break;
  1588. }
  1589. /*
  1590. * We do not load the file, but read the headers for the
  1591. * "Location:", check out that redirecting_url and if it's
  1592. * acceptible (e.g., not a telnet URL when we have that
  1593. * disabled), initiate a new fetch. If that's another
  1594. * redirecting_url, we'll repeat the checks, and fetch
  1595. * initiations if acceptible, until we reach the actual URL, or
  1596. * the redirection limit set in HTAccess.c is exceeded. If the
  1597. * status was 301 indicating that the relocation is permanent,
  1598. * we set the permanent_redirection flag to make it permanent
  1599. * for the current anchor tree (i.e., will persist until the
  1600. * tree is freed or the client exits). If the redirection
  1601. * would include POST content, we seek confirmation from an
  1602. * interactive user, with option to use 303 for 301 (but not
  1603. * for 307), and otherwise refuse the redirection. We also
  1604. * don't allow permanent redirection if we keep POST content.
  1605. * If we don't find the Location header or it's value is
  1606. * zero-length, we display whatever the server returned, and
  1607. * the user should RELOAD that to try again, or make a
  1608. * selection from it if it contains links, or Left-Arrow to the
  1609. * previous document. - FM
  1610. */
  1611. {
  1612. if ((dump_output_immediately || traversal) &&
  1613. do_post &&
  1614. server_status != 303 &&
  1615. server_status != 302 &&
  1616. server_status != 301) {
  1617. /*
  1618. * Don't redirect POST content without approval from an
  1619. * interactive user. - FM
  1620. */
  1621. HTTP_NETCLOSE(s, handle);
  1622. status = -1;
  1623. HTAlert(gettext("Redirection of POST content requires user approval."));
  1624. if (traversal)
  1625. HTProgress(line_buffer);
  1626. goto clean_up;
  1627. }
  1628. HTProgress(line_buffer);
  1629. if (server_status == 301) { /* Moved Permanently */
  1630. if (do_post) {
  1631. /*
  1632. * Don't make the redirection permanent if we have
  1633. * POST content. - FM
  1634. */
  1635. CTRACE((tfp,
  1636. "HTTP: Have POST content. Treating 301 (Permanent) as Temporary.\n"));
  1637. HTAlert(gettext("Have POST content. Treating Permanent Redirection as Temporary.\n"));
  1638. } else {
  1639. permanent_redirection = TRUE;
  1640. }
  1641. }
  1642. doing_redirect = TRUE;
  1643. break;
  1644. }
  1645. case 4:
  1646. /*
  1647. * "I think I goofed!" (Client Error) - FM
  1648. */
  1649. switch (server_status) {
  1650. case 401: /* Unauthorized */
  1651. /*
  1652. * Authorization for orgin server required. If show_401 is
  1653. * set, proceed to showing the 401 body. Otherwise, if we
  1654. * can set up authorization based on the WWW-Authenticate
  1655. * header, and the user provides a username and password,
  1656. * try again. Otherwise, check whether to show the 401
  1657. * body or restore the current document. - FM
  1658. */
  1659. if (show_401)
  1660. break;
  1661. if (HTAA_shouldRetryWithAuth(start_of_data, length, s, NO)) {
  1662. HTTP_NETCLOSE(s, handle);
  1663. if (dump_output_immediately && !authentication_info[0]) {
  1664. fprintf(stderr,
  1665. "HTTP: Access authorization required.\n");
  1666. fprintf(stderr,
  1667. " Use the -auth=id:pw parameter.\n");
  1668. status = HT_NO_DATA;
  1669. goto clean_up;
  1670. }
  1671. CTRACE((tfp, "%s %d %s\n",
  1672. "HTTP: close socket", s,
  1673. "to retry with Access Authorization"));
  1674. _HTProgress(gettext("Retrying with access authorization information."));
  1675. FREE(line_buffer);
  1676. FREE(line_kept_clean);
  1677. #ifdef USE_SSL
  1678. if (using_proxy && !strncmp(url, "https://", 8)) {
  1679. url = arg;
  1680. do_connect = TRUE;
  1681. did_connect = FALSE;
  1682. }
  1683. #endif /* USE_SSL */
  1684. goto try_again;
  1685. } else if (!(traversal || dump_output_immediately) &&
  1686. HTConfirm(gettext("Show the 401 message body?"))) {
  1687. break;
  1688. } else {
  1689. if (traversal || dump_output_immediately)
  1690. HTAlert(FAILED_RETRY_WITH_AUTH);
  1691. HTTP_NETCLOSE(s, handle);
  1692. status = -1;
  1693. goto clean_up;
  1694. }
  1695. case 407:
  1696. /*
  1697. * Authorization for proxy server required. If we are not
  1698. * in fact using a proxy, or show_407 is set, proceed to
  1699. * showing the 407 body. Otherwise, if we can set up
  1700. * authorization based on the Proxy-Authenticate header,
  1701. * and the user provides a username and password, try
  1702. * again. Otherwise, check whether to show the 401 body or
  1703. * restore the current document. - FM & AJL
  1704. */
  1705. if (!using_proxy || show_407)
  1706. break;
  1707. if (HTAA_shouldRetryWithAuth(start_of_data, length, s, YES)) {
  1708. HTTP_NETCLOSE(s, handle);
  1709. if (dump_output_immediately && !proxyauth_info[0]) {
  1710. fprintf(stderr,
  1711. "HTTP: Proxy authorization required.\n");
  1712. fprintf(stderr,
  1713. " Use the -pauth=id:pw parameter.\n");
  1714. status = HT_NO_DATA;
  1715. goto clean_up;
  1716. }
  1717. CTRACE((tfp, "%s %d %s\n",
  1718. "HTTP: close socket", s,
  1719. "to retry with Proxy Authorization"));
  1720. _HTProgress(HTTP_RETRY_WITH_PROXY);
  1721. FREE(line_buffer);
  1722. FREE(line_kept_clean);
  1723. goto try_again;
  1724. } else if (!(traversal || dump_output_immediately) &&
  1725. HTConfirm(gettext("Show the 407 message body?"))) {
  1726. if (!dump_output_immediately &&
  1727. format_out == HTAtom_for("www/download")) {
  1728. /*
  1729. * Convert a download request to a presentation
  1730. * request for interactive users. - FM
  1731. */
  1732. format_out = WWW_PRESENT;
  1733. }
  1734. break;
  1735. } else {
  1736. if (traversal || dump_output_immediately)
  1737. HTAlert(FAILED_RETRY_WITH_PROXY);
  1738. HTTP_NETCLOSE(s, handle);
  1739. status = -1;
  1740. goto clean_up;
  1741. }
  1742. case 408:
  1743. /*
  1744. * Request Timeout. Show the status message and restore
  1745. * the current document. - FM
  1746. */
  1747. HTAlert(line_buffer);
  1748. HTTP_NETCLOSE(s, handle);
  1749. status = HT_NO_DATA;
  1750. goto done;
  1751. default:
  1752. /*
  1753. * 400 Bad Request.
  1754. * 402 Payment Required.
  1755. * 403 Forbidden.
  1756. * 404 Not Found.
  1757. * 405 Method Not Allowed.
  1758. * 406 Not Acceptable.
  1759. * 409 Conflict.
  1760. * 410 Gone.
  1761. * 411 Length Required.
  1762. * 412 Precondition Failed.
  1763. * 413 Request Entity Too Large.
  1764. * 414 Request-URI Too Long.
  1765. * 415 Unsupported Media Type.
  1766. * 416 List Response (for content negotiation).
  1767. * > 416 is unknown.
  1768. * Show the status message, and display the returned text
  1769. * if we are not doing a traversal. - FM
  1770. */
  1771. HTAlert(line_buffer);
  1772. if (traversal) {
  1773. HTTP_NETCLOSE(s, handle);
  1774. status = -1;
  1775. goto clean_up;
  1776. }
  1777. if (!dump_output_immediately &&
  1778. format_out == HTAtom_for("www/download")) {
  1779. /*
  1780. * Convert a download request to a presentation request
  1781. * for interactive users. - FM
  1782. */
  1783. format_out = WWW_PRESENT;
  1784. }
  1785. break;
  1786. } /* case 4 switch */
  1787. break;
  1788. case 5:
  1789. /*
  1790. * "I think YOU goofed!" (server error)
  1791. * 500 Internal Server Error
  1792. * 501 Not Implemented
  1793. * 502 Bad Gateway
  1794. * 503 Service Unavailable
  1795. * 504 Gateway Timeout
  1796. * 505 HTTP Version Not Supported
  1797. * > 505 is unknown.
  1798. * Should always include a message, which we always should
  1799. * display. - FM
  1800. */
  1801. HTAlert(line_buffer);
  1802. if (traversal) {
  1803. HTTP_NETCLOSE(s, handle);
  1804. status = -1;
  1805. goto clean_up;
  1806. }
  1807. if (!dump_output_immediately &&
  1808. format_out == HTAtom_for("www/download")) {
  1809. /*
  1810. * Convert a download request to a presentation request for
  1811. * interactive users. - FM
  1812. */
  1813. format_out = WWW_PRESENT;
  1814. }
  1815. break;
  1816. default:
  1817. /*
  1818. * Bad or unknown server_status number. Take a chance and hope
  1819. * there is something to display. - FM
  1820. */
  1821. HTAlert(gettext("Unknown status reply from server!"));
  1822. HTAlert(line_buffer);
  1823. if (traversal) {
  1824. HTTP_NETCLOSE(s, handle);
  1825. status = -1;
  1826. goto clean_up;
  1827. }
  1828. if (!dump_output_immediately &&
  1829. format_out == HTAtom_for("www/download")) {
  1830. /*
  1831. * Convert a download request to a presentation request for
  1832. * interactive users. - FM
  1833. */
  1834. format_out = WWW_PRESENT;
  1835. }
  1836. break;
  1837. } /* Switch on server_status/100 */
  1838. } /* Full HTTP reply */
  1839. } /* scope of fields */
  1840. /*
  1841. * The user may have pressed the 'z'ap key during the pause caused by one
  1842. * of the HTAlerts above if the server reported an error, to skip loading
  1843. * of the error response page. Checking here before setting up the stream
  1844. * stack and feeding it data avoids doing unnecessary work, it also can
  1845. * avoid unnecessarily pushing a loaded document out of the cache to make
  1846. * room for the unwanted error page. - kw
  1847. */
  1848. if (HTCheckForInterrupt()) {
  1849. HTTP_NETCLOSE(s, handle);
  1850. if (doing_redirect) {
  1851. /*
  1852. * Impatient user. - FM
  1853. */
  1854. CTRACE((tfp, "HTTP: Interrupted followup read.\n"));
  1855. _HTProgress(CONNECTION_INTERRUPTED);
  1856. }
  1857. status = HT_INTERRUPTED;
  1858. goto clean_up;
  1859. }
  1860. /*
  1861. * Set up the stream stack to handle the body of the message.
  1862. */
  1863. if (do_head || keep_mime_headers) {
  1864. /*
  1865. * It was a HEAD request, or we want the headers and source.
  1866. */
  1867. start_of_data = line_kept_clean;
  1868. #ifdef SH_EX /* FIX BUG by kaz@maczuka.hitachi.ibaraki.jp */
  1869. /* GIF file contains \0, so strlen does not return the data length */
  1870. length = real_length_of_line;
  1871. #else
  1872. length = rawlength;
  1873. #endif
  1874. format_in = HTAtom_for("text/plain");
  1875. } else if (doing_redirect) {
  1876. format_in = HTAtom_for("message/x-http-redirection");
  1877. StrAllocCopy(anAnchor->content_type, HTAtom_name(format_in));
  1878. if (traversal) {
  1879. format_out = WWW_DEBUG;
  1880. if (!sink)
  1881. sink = HTErrorStream();
  1882. } else if (!dump_output_immediately &&
  1883. format_out == HTAtom_for("www/download")) {
  1884. /*
  1885. * Convert a download request to a presentation request for
  1886. * interactive users. - FM
  1887. */
  1888. format_out = WWW_PRESENT;
  1889. }
  1890. }
  1891. target = HTStreamStack(format_in,
  1892. format_out,
  1893. sink, anAnchor);
  1894. if (target == NULL) {
  1895. char *buffer = NULL;
  1896. HTTP_NETCLOSE(s, handle);
  1897. HTSprintf0(&buffer, CANNOT_CONVERT_I_TO_O,
  1898. HTAtom_name(format_in), HTAtom_name(format_out));
  1899. _HTProgress(buffer);
  1900. FREE(buffer);
  1901. status = -1;
  1902. goto clean_up;
  1903. }
  1904. /*
  1905. * Recycle the first chunk of data, in all cases.
  1906. */
  1907. (*target->isa->put_block) (target, start_of_data, length);
  1908. /*
  1909. * Go pull the bulk of the data down.
  1910. */
  1911. rv = HTCopy(anAnchor, s, (void *) handle, target);
  1912. /*
  1913. * If we get here with doing_redirect set, it means that we were looking
  1914. * for a Location header. We either have got it now in redirecting_url -
  1915. * in that case the stream should not have loaded any data. Or we didn't
  1916. * get it, in that case the stream may have presented the message body
  1917. * normally. - kw
  1918. */
  1919. if (rv == -1) {
  1920. /*
  1921. * Intentional interrupt before data were received, not an error
  1922. */
  1923. /* (*target->isa->_abort)(target, NULL); *//* already done in HTCopy */
  1924. if (doing_redirect && traversal)
  1925. status = -1;
  1926. else
  1927. status = HT_INTERRUPTED;
  1928. HTTP_NETCLOSE(s, handle);
  1929. goto clean_up;
  1930. }
  1931. if (rv == -2) {
  1932. /*
  1933. * Aw hell, a REAL error, maybe cuz it's a dumb HTTP0 server
  1934. */
  1935. (*target->isa->_abort) (target, NULL);
  1936. if (doing_redirect && redirecting_url) {
  1937. /*
  1938. * Got a location before the error occurred? Then consider it an
  1939. * interrupt but proceed below as normal. - kw
  1940. */
  1941. /* do nothing here */
  1942. } else {
  1943. HTTP_NETCLOSE(s, handle);
  1944. if (!doing_redirect && !already_retrying && !do_post) {
  1945. CTRACE((tfp, "HTTP: Trying again with HTTP0 request.\n"));
  1946. /*
  1947. * May as well consider it an interrupt -- right?
  1948. */
  1949. FREE(line_buffer);
  1950. FREE(line_kept_clean);
  1951. extensions = NO;
  1952. already_retrying = TRUE;
  1953. _HTProgress(RETRYING_AS_HTTP0);
  1954. goto try_again;
  1955. } else {
  1956. status = HT_NOT_LOADED;
  1957. goto clean_up;
  1958. }
  1959. }
  1960. }
  1961. /*
  1962. * Free if complete transmission (socket was closed before return). Close
  1963. * socket if partial transmission (was freed on abort).
  1964. */
  1965. if (rv != HT_INTERRUPTED && rv != -2) {
  1966. (*target->isa->_free) (target);
  1967. } else {
  1968. HTTP_NETCLOSE(s, handle);
  1969. }
  1970. if (doing_redirect) {
  1971. if (redirecting_url) {
  1972. /*
  1973. * Set up for checking redirecting_url in LYGetFile.c for
  1974. * restrictions before we seek the document at that Location. - FM
  1975. */
  1976. CTRACE((tfp, "HTTP: Picked up location '%s'\n",
  1977. redirecting_url));
  1978. if (rv == HT_INTERRUPTED) {
  1979. /*
  1980. * Intentional interrupt after data were received, not an error
  1981. * (probably). We take it as a user request to abandon the
  1982. * redirection chain.
  1983. *
  1984. * This could reasonably be changed (by just removing this
  1985. * block), it would make sense if there are redirecting
  1986. * resources that "hang" after sending the headers. - kw
  1987. */
  1988. FREE(redirecting_url);
  1989. CTRACE((tfp, "HTTP: Interrupted followup read.\n"));
  1990. status = HT_INTERRUPTED;
  1991. goto clean_up;
  1992. }
  1993. HTProgress(line_buffer);
  1994. if (server_status == 305) { /* Use Proxy */
  1995. /*
  1996. * Make sure the proxy field ends with a slash. - FM
  1997. */
  1998. if (redirecting_url[strlen(redirecting_url) - 1]
  1999. != '/')
  2000. StrAllocCat(redirecting_url, "/");
  2001. /*
  2002. * Append our URL. - FM
  2003. */
  2004. StrAllocCat(redirecting_url, anAnchor->address);
  2005. CTRACE((tfp, "HTTP: Proxy URL is '%s'\n",
  2006. redirecting_url));
  2007. }
  2008. if (!do_post ||
  2009. server_status == 303 ||
  2010. server_status == 302) {
  2011. /*
  2012. * We don't have POST content (nor support PUT or DELETE), or
  2013. * the status is "See Other" or "General Redirection" and we
  2014. * can convert to GET, so go back and check out the new URL. -
  2015. * FM
  2016. */
  2017. status = HT_REDIRECTING;
  2018. goto clean_up;
  2019. }
  2020. /*
  2021. * Make sure the user wants to redirect the POST content, or treat
  2022. * as GET - FM & DK
  2023. */
  2024. switch (HTConfirmPostRedirect(redirecting_url,
  2025. server_status)) {
  2026. /*
  2027. * User failed to confirm. Abort the fetch.
  2028. */
  2029. case 0:
  2030. doing_redirect = FALSE;
  2031. FREE(redirecting_url);
  2032. status = HT_NO_DATA;
  2033. goto clean_up;
  2034. /*
  2035. * User wants to treat as GET with no content. Go back to
  2036. * check out the URL.
  2037. */
  2038. case 303:
  2039. break;
  2040. /*
  2041. * Set the flag to retain the POST content and go back to check
  2042. * out the URL. - FM
  2043. */
  2044. default:
  2045. redirect_post_content = TRUE;
  2046. }
  2047. /* Lou's old comment: - FM */
  2048. /* OK, now we've got the redirection URL temporarily stored
  2049. in external variable redirecting_url, exported from HTMIME.c,
  2050. since there's no straightforward way to do this in the library
  2051. currently. Do the right thing. */
  2052. status = HT_REDIRECTING;
  2053. } else {
  2054. status = traversal ? -1 : HT_LOADED;
  2055. }
  2056. } else {
  2057. /*
  2058. * If any data were received, treat as a complete transmission
  2059. */
  2060. status = HT_LOADED;
  2061. }
  2062. /*
  2063. * Clean up
  2064. */
  2065. clean_up:
  2066. FREE(line_buffer);
  2067. FREE(line_kept_clean);
  2068. done:
  2069. /*
  2070. * Clear out on exit, just in case.
  2071. */
  2072. do_head = FALSE;
  2073. do_post = FALSE;
  2074. reloading = FALSE;
  2075. #ifdef USE_SSL
  2076. do_connect = FALSE;
  2077. did_connect = FALSE;
  2078. FREE(connect_host);
  2079. if (handle) {
  2080. SSL_free(handle);
  2081. SSL_handle = handle = NULL;
  2082. }
  2083. #endif /* USE_SSL */
  2084. return status;
  2085. }
  2086. /* Protocol descriptor
  2087. */
  2088. #ifdef GLOBALDEF_IS_MACRO
  2089. #define _HTTP_C_GLOBALDEF_1_INIT { "http", HTLoadHTTP, 0}
  2090. GLOBALDEF(HTProtocol, HTTP, _HTTP_C_GLOBALDEF_1_INIT);
  2091. #define _HTTP_C_GLOBALDEF_2_INIT { "https", HTLoadHTTP, 0}
  2092. GLOBALDEF(HTProtocol, HTTPS, _HTTP_C_GLOBALDEF_2_INIT);
  2093. #else
  2094. GLOBALDEF HTProtocol HTTP =
  2095. {"http", HTLoadHTTP, 0};
  2096. GLOBALDEF HTProtocol HTTPS =
  2097. {"https", HTLoadHTTP, 0};
  2098. #endif /* GLOBALDEF_IS_MACRO */