/* Determine file format from file name -- string version ** ------------------------------------------------------ */ PUBLIC char *HTFileMimeType ARGS2 ( WWW_CONST char *, filename, WWW_CONST char *, default_type) { HTAtom *pencoding; HTFormat format; int compressed; format = HTFileFormat (filename, &pencoding, HTAtom_for (default_type), &compressed); if (HTAtom_name (format)) return HTAtom_name (format); else return default_type; }
static void SetupFilename(bstring **filename, const char *sug_filename) { HTFormat format; HTAtom *encoding; char *cp; BStrCopy0(*filename, sug_filename); /* add suggestion info */ BStrAlloc(*filename, LY_MAXPATH); /* FIXME */ change_sug_filename((*filename)->str); if (!(HTisDocumentSource()) && (cp = strrchr((*filename)->str, '.')) != NULL) { format = HTFileFormat((*filename)->str, &encoding, NULL); CTRACE((tfp, "... format %s\n", format->name)); if (!strcasecomp(format->name, "text/html") || !IsUnityEnc(encoding)) { (*filename)->len = (int) (cp - (*filename)->str); BStrCat0(*filename, TEXT_SUFFIX); } } CTRACE((tfp, "... result %s\n", (*filename)->str)); }
/* Load a document ** --------------- ** ** On entry, ** addr must point to the fully qualified hypertext reference. ** This is the physsical address of the file ** ** On exit, ** returns <0 Error has occured. ** HTLOADED OK ** */ PUBLIC int HTLoadFile ARGS4 ( WWW_CONST char *, addr, HTParentAnchor *, anchor, HTFormat, format_out, HTStream *, sink ) { char * filename; HTFormat format; int fd = -1; /* Unix file descriptor number = INVALID */ char * nodename = 0; char * newname=0; /* Simplified name of file */ HTAtom * encoding; /* @@ not used yet */ int compressed; extern char *HTgeticonname(HTFormat, char *); /* Reduce the filename to a basic form (hopefully unique!) */ StrAllocCopy(newname, addr); filename=HTParse(newname, "", PARSE_PATH|PARSE_PUNCTUATION); nodename=HTParse(newname, "", PARSE_HOST); free(newname); format = HTFileFormat(filename, &encoding, WWW_PLAINTEXT, &compressed); #ifdef vms /* Assume that the file is in Unix-style syntax if it contains a '/' after the leading one @@ */ { char * vmsname = strchr(filename + 1, '/') ? vms_name(nodename, filename) : filename + 1; fd = open(vmsname, O_RDONLY, 0); /* If the file wasn't VMS syntax, then perhaps it is ultrix */ if (fd<0) { char ultrixname[INFINITY]; #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTFile: Can't open as %s\n", vmsname); #endif sprintf(ultrixname, "%s::\"%s\"", nodename, filename); fd = open(ultrixname, O_RDONLY, 0); if (fd<0) { #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTFile: Can't open as %s\n", ultrixname); #endif } } } #else free(filename); /* For unix, we try to translate the name into the name of a transparently ** mounted file. ** ** Not allowed in secure (HTClienntHost) situations TBL 921019 */ #ifndef NO_UNIX_IO /* Need protection here for telnet server but not httpd server */ { /* try local file system */ char * localname = HTLocalName(addr); struct stat dir_info; if (!localname) goto suicide; #ifdef GOT_READ_DIR /* Multiformat handling ** ** If needed, scan directory to find a good file. ** Bug: we don't stat the file to find the length */ if ( (strlen(localname) > strlen(MULTI_SUFFIX)) && (0==strcmp(localname + strlen(localname) - strlen(MULTI_SUFFIX), MULTI_SUFFIX))) { DIR *dp; STRUCT_DIRENT * dirbuf; float best = NO_VALUE_FOUND; /* So far best is bad */ HTFormat best_rep = NULL; /* Set when rep found */ STRUCT_DIRENT best_dirbuf; /* Best dir entry so far */ char * base = strrchr(localname, '/'); int baselen; if (!base || base == localname) goto forget_multi; *base++ = 0; /* Just got directory name */ baselen = strlen(base)- strlen(MULTI_SUFFIX); base[baselen] = 0; /* Chop off suffix */ dp = opendir(localname); if (!dp) { forget_multi: free(localname); return HTLoadError(sink, 500, "Multiformat: directory scan failed."); } while (dirbuf = readdir(dp)) { /* while there are directory entries to be read */ if (dirbuf->d_ino == 0) continue; /* if the entry is not being used, skip it */ if (!strncmp(dirbuf->d_name, base, baselen)) { HTFormat rep = HTFileFormat(dirbuf->d_name, &encoding, WWW_PLAINTEXT, &compressed); float value = HTStackValue(rep, format_out, HTFileValue(dirbuf->d_name), 0.0 /* @@@@@@ */); if (value != NO_VALUE_FOUND) { #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTFile: value of presenting %s is %f\n", HTAtom_name(rep), value); #endif if (value > best) { best_rep = rep; best = value; best_dirbuf = *dirbuf; } } /* if best so far */ } /* if match */ } /* end while directory entries left to read */ closedir(dp); if (best_rep) { format = best_rep; base[-1] = '/'; /* Restore directory name */ base[0] = 0; StrAllocCat(localname, best_dirbuf.d_name); goto open_file; } else { /* If not found suitable file */ free(localname); return HTLoadError(sink, 403, /* List formats? */ "Could not find suitable representation for transmission."); } /*NOTREACHED*/ } /* if multi suffix */ /* ** Check to see if the 'localname' is in fact a directory. If it is ** create a new hypertext object containing a list of files and ** subdirectories contained in the directory. All of these are links ** to the directories or files listed. ** NB This assumes the existance of a type 'STRUCT_DIRENT', which will ** hold the directory entry, and a type 'DIR' which is used to point to ** the current directory being read. */ if (stat(localname,&dir_info) == -1) { /* get file information */ /* if can't read file information */ #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTFile: can't stat %s\n", localname); #endif } else { /* Stat was OK */ if (((dir_info.st_mode) & S_IFMT) == S_IFDIR) { /* if localname is a directory */ /* ** ** Read the localdirectory and present a nicely formatted list to the user ** Re-wrote most of the read directory code here, excepting for the checking ** access. ** ** Author: Charles Henrich ([email protected]) 10-09-93 ** ** This is still pretty messy, need to go through and clean it up at some point ** */ /* Define some parameters that everyone should already have */ #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif #ifndef BUFSIZ #define BUFSIZ 4096 #endif char filepath[MAXPATHLEN]; char buffer[4096]; char *ptr; char *dataptr; HText * HT; HTFormat format; HTAtom *pencoding; struct stat statbuf; STRUCT_DIRENT * dp; DIR *dfp; int cmpr; int count; #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr,"%s is a directory\n",localname); #endif /* Check directory access. ** Selective access means only those directories containing a ** marker file can be browsed */ if (HTDirAccess == HT_DIR_FORBID) { free(localname); return HTLoadError(sink, 403, "Directory browsing is not allowed."); } if (HTDirAccess == HT_DIR_SELECTIVE) { char * enable_file_name = malloc(strlen(localname)+ 1 + strlen(HT_DIR_ENABLE_FILE) + 1); strcpy(enable_file_name, localname); strcat(enable_file_name, "/"); strcat(enable_file_name, HT_DIR_ENABLE_FILE); if (stat(enable_file_name, &statbuf) != 0) { free(localname); return HTLoadError(sink, 403, "Selective access is not enabled for this directory."); } } dfp = opendir(localname); if (!dfp) { free(localname); return HTLoadError(sink, 403, "This directory is not readable."); } /* Suck the directory up into a list to be sorted */ HTSortInit(); for(dp=readdir(dfp);dp != NULL;dp=readdir(dfp)) { ptr = malloc(strlen(dp->d_name)+1); if(ptr == NULL) { return HTLoadError(sink, 403, "Ran out of memory in directory read!"); } strcpy(ptr,dp->d_name); HTSortAdd(ptr); } closedir(dfp); /* Sort the dir list */ HTSortSort(); /* Start a new HTML page */ HT = HText_new(); HText_beginAppend(HT); HText_appendText(HT, "<H1>Local Directory "); HText_appendText(HT, localname); HText_appendText(HT, "</H1>\n"); HText_appendText(HT,"<DL>\n"); /* Sort the list and then spit it out in a nice form */ /* How this for a disgusting loop :) */ for(count=0,dataptr=HTSortFetch(count); dataptr != NULL; free(dataptr), count++, dataptr=HTSortFetch(count)) { /* We dont want to see . */ if(strcmp(dataptr,".") == 0) continue; /* If its .. *and* the current directory is / dont show anything, otherwise /* print out a nice Parent Directory entry. /* */ if(strcmp(dataptr,"..") == 0) { if(strcmp(localname,"/") != 0) { strcpy(buffer,localname); ptr = strrchr(buffer, '/'); if(ptr != NULL) *ptr='\0'; if(buffer[0] == '\0') strcpy(buffer,"/"); HText_appendText(HT,"<DD><A HREF=\""); HText_appendText(HT, buffer); HText_appendText(HT,"\"><IMG SRC=\""); HText_appendText(HT, HTgeticonname(NULL, "directory")); HText_appendText(HT,"\"> Parent Directory</a>"); continue; } else { continue; } } /* Get the filesize information from a stat, if we cant stat it, we probably */ /* cant read it either, so ignore it. */ sprintf(filepath,"%s/%s",localname, dataptr); if(stat(filepath, &statbuf) == -1) continue; HText_appendText(HT,"<DD><A HREF=\""); HText_appendText (HT, localname); if(localname[strlen(localname)-1] != '/') { HText_appendText (HT, "/"); } HText_appendText (HT, dataptr); HText_appendText (HT, "\">"); /* If its a directory, dump out a dir icon, dont bother with anything else */ /* if it is a file try and figure out what type of file it is, and grab */ /* the appropriate icon. If we cant figure it out, call it text. If its */ /* a compressed file, call it binary no matter what */ if(statbuf.st_mode & S_IFDIR) { sprintf(buffer,"%s",dataptr); HText_appendText(HT, "<IMG SRC=\""); HText_appendText(HT, HTgeticonname(NULL, "directory")); HText_appendText(HT, "\"> "); } else { sprintf(buffer,"%s (%d bytes)", dataptr, (int)statbuf.st_size); format = HTFileFormat(dataptr, &pencoding, WWW_SOURCE, &cmpr); /* If its executable then call it application, else it might as well be text */ if(cmpr == 0) { HText_appendText(HT, "<IMG SRC=\""); if((statbuf.st_mode & S_IXUSR) || (statbuf.st_mode & S_IXGRP) || (statbuf.st_mode & S_IXOTH)) { HText_appendText(HT, HTgeticonname(format, "application")); } else { HText_appendText(HT, HTgeticonname(format, "text")); } HText_appendText(HT, "\"> "); } else { HText_appendText(HT, "<IMG SRC=\""); HText_appendText(HT, HTgeticonname(NULL, "application")); HText_appendText(HT, "\"> "); } } /* Spit out the anchor */ HText_appendText (HT, buffer); HText_appendText (HT, "</A>\n"); } /* End of list, clean up and we are done */ HText_appendText (HT, "</DL>\n"); HText_endAppend (HT); free(localname); return HT_LOADED; } /* end if localname is directory */ } /* end if file stat worked */ /* End of directory reading section */ #endif open_file: { FILE * fp = fopen(localname,"r"); #ifndef DISABLE_TRACE if(www2Trace) fprintf (stderr, "HTFile: Opening `%s' gives %p\n", localname, (void*)fp); #endif if (fp) { /* Good! */ if (HTEditable(localname)) { HTAtom * put = HTAtom_for("PUT"); HTList * methods = HTAnchor_methods(anchor); if (HTList_indexOf(methods, put) == (-1)) { HTList_addObject(methods, put); } } free(localname); HTParseFile(format, format_out, anchor, fp, sink, compressed); /* This is closed elsewhere...SWP fclose(fp); */ return HT_LOADED; } /* If succesfull open */ } /* scope of fp */ } /* local unix file system */ #endif #endif /* Now, as transparently mounted access has failed, we try FTP. */ suicide: /* return HTFTPLoad(addr, anchor, format_out, sink); */ /* Sorry Charlie...if we are given a file:// URL and it fails, then it fails! Do NOT FTP!! */ return HT_NOT_LOADED; }
/* HTVMSBrowseDir() ** ** This function generates a directory listing as an HTML-object ** for local file URL's. It assumes the first two elements of ** of the path are a device followed by a directory: ** ** file://localhost/device/directory[/[foo]] ** ** Will not accept 000000 as a directory name. ** Will offer links to parent through the top directory, unless ** a terminal slash was included in the calling URL. ** ** Returns HT_LOADED on success, HTLoadError() messages on error. ** ** Developed for Lynx by Foteos Macrides ([email protected]). */ PUBLIC int HTVMSBrowseDir ARGS4( CONST char *, address, HTParentAnchor *, anchor, HTFormat, format_out, HTStream *, sink ) { HTStructured* target; HTStructuredClass targetClass; char *pathname = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION); char *tail = NULL; char *title = NULL; char *header = NULL; char *parent = NULL; char *relative = NULL; char *cp, *cp1; int pathend, len; DIR *dp; struct stat file_info; time_t NowTime; static char ThisYear[8]; VMSEntryInfo *entry_info = 0; char string_buffer[64]; HTUnEscape(pathname); CTRACE((tfp,"HTVMSBrowseDir: Browsing `%s\'\n", pathname)); /* * Require at least two elements (presumably a device and directory) * and disallow the device root (000000 directory). Symbolic paths * (e.g., sys$help) should have been translated and expanded (e.g., * to /sys$sysroot/syshlp) before calling this routine. */ if (((*pathname != '/') || (cp = strchr(pathname+1, '/')) == NULL || *(cp + 1) == '\0' || 0 == strncmp((cp + 1), "000000", 6)) || (dp = HTVMSopendir(pathname)) == NULL) { FREE(pathname); return HTLoadError(sink, 403, COULD_NOT_ACCESS_DIR); } /* * Set up the output stream. */ _HTProgress (BUILDING_DIR_LIST); if (UCLYhndl_HTFile_for_unspec >= 0) { HTAnchor_setUCInfoStage(anchor, UCLYhndl_HTFile_for_unspec, UCT_STAGE_PARSER, UCT_SETBY_DEFAULT); } target = HTML_new(anchor, format_out, sink); targetClass = *(target->isa); /* * Set up the offset string of the anchor reference, * and strings for the title and header. */ cp = strrchr(pathname, '/'); /* find lastslash */ StrAllocCopy(tail, (cp+1)); /* take slash off the beginning */ if (*tail != '\0') { StrAllocCopy(title, tail); *cp = '\0'; if ((cp1=strrchr(pathname, '/')) != NULL && cp1 != pathname && strncmp((cp1+1), "000000", 6)) StrAllocCopy(parent, (cp1+1)); *cp = '/'; } else { pathname[strlen(pathname)-1] = '\0'; cp = strrchr(pathname, '/'); StrAllocCopy(title, (cp+1)); pathname[strlen(pathname)] = '/'; } StrAllocCopy(header, pathname); /* * Initialize path name for HTStat(). */ pathend = strlen(pathname); if (*(pathname+pathend-1) != '/') { StrAllocCat(pathname, "/"); pathend++; } /* * Output the title and header. */ START(HTML_HTML); PUTC('\n'); START(HTML_HEAD); PUTC('\n'); HTUnEscape(title); START(HTML_TITLE); PUTS(title); PUTS(" directory"); END(HTML_TITLE); PUTC('\n'); FREE(title); END(HTML_HEAD); PUTC('\n'); START(HTML_BODY); PUTC('\n'); HTUnEscape(header); START(HTML_H1); PUTS(header); END(HTML_H1); PUTC('\n'); if (HTDirReadme == HT_DIR_README_TOP) { FILE * fp; if (header[strlen(header)-1] != '/') StrAllocCat(header, "/"); StrAllocCat(header, HT_DIR_README_FILE); if ((fp = fopen(header, "r")) != NULL) { START(HTML_PRE); for(;;) { char c = fgetc(fp); if (c == (char)EOF) break; #ifdef NOTDEFINED switch (c) { case '&': case '<': case '>': PUTC('&'); PUTC('#'); PUTC((char)(c / 10)); PUTC((char) (c % 10)); PUTC(';'); break; default: PUTC(c); } #else PUTC(c); #endif /* NOTDEFINED */ } END(HTML_PRE); fclose(fp); } } FREE(header); if (parent) { HTSprintf0(&relative, "%s/..", tail); HTStartAnchor(target, "", relative); PUTS("Up to "); HTUnEscape(parent); PUTS(parent); END(HTML_A); START(HTML_P); PUTC('\n'); FREE(relative); FREE(parent); } /* * Set up the date comparison. */ NowTime = time(NULL); strcpy(ThisYear, (char *)ctime(&NowTime)+20); ThisYear[4] = '\0'; /* * Now, generate the Btree and put it out to the output stream. */ { char dottest = 2; /* To avoid two strcmp() each time */ STRUCT_DIRENT *dirbuf; HTBTree *bt; /* Set up sort key and initialize BTree */ bt = HTBTree_new((HTComparer) compare_VMSEntryInfo_structs); /* Build tree */ while ((dirbuf = HTVMSreaddir(dp))) { HTAtom *encoding = NULL; HTFormat format; /* Skip if not used */ if (!dirbuf->d_ino) { continue; } /* Current and parent directories are never shown in list */ if (dottest && (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))) { dottest--; continue; } /* Don't show the selective enabling file * unless version numbers are included */ if (!strcasecomp(dirbuf->d_name, HT_DIR_ENABLE_FILE)) { continue; } /* Skip files beginning with a dot? */ if ((no_dotfiles || !show_dotfiles) && *dirbuf->d_name == '.') { continue; } /* OK, make an lstat() and get a key ready. */ *(pathname+pathend) = '\0'; StrAllocCat(pathname, dirbuf->d_name); if (HTStat(pathname, &file_info)) { /* for VMS the failure here means the file is not readable... we however continue to browse through the directory... */ continue; } entry_info = (VMSEntryInfo *)malloc(sizeof(VMSEntryInfo)); if (entry_info == NULL) outofmem(__FILE__, "HTVMSBrowseDir"); entry_info->type = 0; entry_info->size = 0; entry_info->date = 0; entry_info->filename = 0; entry_info->display = TRUE; /* Get the type */ format = HTFileFormat(dirbuf->d_name, &encoding, (CONST char **)&cp); if (!cp) { if(!strncmp(HTAtom_name(format), "application",11)) { cp = HTAtom_name(format) + 12; if(!strncmp(cp,"x-", 2)) cp += 2; } else cp = HTAtom_name(format); } StrAllocCopy(entry_info->type, cp); StrAllocCopy(entry_info->filename, dirbuf->d_name); if (S_ISDIR(file_info.st_mode)) { /* strip .DIR part... */ char *dot; dot = strstr(entry_info->filename, ".DIR"); if (dot) *dot = '\0'; LYLowerCase(entry_info->filename); StrAllocCopy(entry_info->type, "Directory"); } else { if ((cp = strstr(entry_info->filename, "READ")) == NULL) { cp = entry_info->filename; } else { cp += 4; if (!strncmp(cp, "ME", 2)) { cp += 2; while (cp && *cp && *cp != '.') { cp++; } } else if (!strncmp(cp, ".ME", 3)) { cp = (entry_info->filename + strlen(entry_info->filename)); } else { cp = entry_info->filename; } } LYLowerCase(cp); if (((len = strlen(entry_info->filename)) > 2) && entry_info->filename[len-1] == 'z') { if (entry_info->filename[len-2] == '.' || entry_info->filename[len-2] == '_') entry_info->filename[len-1] = 'Z'; } } /* Get the date */ { char *t = (char *)ctime((CONST time_t *)&file_info.st_ctime); *(t+24) = '\0'; StrAllocCopy(entry_info->date, (t+4)); *((entry_info->date)+7) = '\0'; if ((atoi((t+19))) < atoi(ThisYear)) StrAllocCat(entry_info->date, (t+19)); else { StrAllocCat(entry_info->date, (t+11)); *((entry_info->date)+12) = '\0'; } } /* Get the size */ if (!S_ISDIR(file_info.st_mode)) entry_info->size = (unsigned int)file_info.st_size; else entry_info->size = 0; /* Now, update the BTree etc. */ if(entry_info->display) { CTRACE((tfp,"Adding file to BTree: %s\n", entry_info->filename)); HTBTree_add(bt, entry_info); } } /* End while HTVMSreaddir() */ FREE(pathname); HTVMSclosedir(dp); START(HTML_PRE); /* * Run through the BTree printing out in order */ { HTBTElement * ele; int i; for (ele = HTBTree_next(bt, NULL); ele != NULL; ele = HTBTree_next(bt, ele)) { entry_info = (VMSEntryInfo *)HTBTree_object(ele); /* Output the date */ if(entry_info->date) { PUTS(entry_info->date); PUTS(" "); } else PUTS(" * "); /* Output the type */ if(entry_info->type) { for(i = 0; entry_info->type[i] != '\0' && i < 15; i++) PUTC(entry_info->type[i]); for(; i < 17; i++) PUTC(' '); } /* Output the link for the name */ HTDirEntry(target, tail, entry_info->filename); PUTS(entry_info->filename); END(HTML_A); /* Output the size */ if(entry_info->size) { if(entry_info->size < 1024) sprintf(string_buffer," %d bytes", entry_info->size); else sprintf(string_buffer," %dKb", entry_info->size/1024); PUTS(string_buffer); } PUTC('\n'); /* end of this entry */ free_VMSEntryInfo_contents(entry_info); } } HTBTreeAndObject_free(bt); } /* End of both BTree loops */ /* * Complete the output stream. */ END(HTML_PRE); PUTC('\n'); END(HTML_BODY); PUTC('\n'); END(HTML_HTML); PUTC('\n'); FREE(tail); FREE_TARGET; return HT_LOADED; } /* End of directory reading section */
/* Load Document from HTTP Server HTLoadHTTP() ** ============================== ** ** Given a hypertext address, this routine loads a document. ** ** ** On entry, ** arg is the hypertext reference of the article to be loaded. ** gate is nill if no gateway, else the gateway address. ** ** On exit, ** returns >=0 If no error, a good socket number ** <0 Error. ** ** The socket must be closed by the caller after the document has been ** read. ** */ PUBLIC int HTLoadHTTP ARGS4 (CONST char *, arg, CONST char *, gate, HTAnchor *, anAnchor, int, diag) { int s; /* Socket number for returned data */ char *command; /* The whole command */ int status; /* tcp return */ char host[256]; /* Hold on to the host */ SockA soc_address; /* Binary network address */ SockA * sin = &soc_address; if (!arg) return -3; /* Bad if no name sepcified */ if (!*arg) return -2; /* Bad if name had zero length */ /* Set up defaults: */ #ifdef DECNET sin->sdn_family = AF_DECnet; /* Family = DECnet, host order */ sin->sdn_objnum = DNP_OBJ; /* Default: http object number */ #else /* Internet */ sin->sin_family = AF_INET; /* Family = internet, host order */ sin->sin_port = htons(TCP_PORT); /* Default: http port */ #endif if (TRACE) { if (gate) fprintf(stderr, "HTTPAccess: Using gateway %s for %s\n", gate, arg); else fprintf(stderr, "HTTPAccess: Direct access for %s\n", arg); } /* Get node name and optional port number: */ { char *p1 = HTParse(gate ? gate : arg, "", PARSE_HOST); strcpy(host, p1); int status = HTParseInet(sin, p1); /* TBL 920622 */ free(p1); if (status) return status; /* No such host for example */ } /* Now, let's get a socket set up from the server for the sgml data: */ #ifdef DECNET s = socket(AF_DECnet, SOCK_STREAM, 0); #else s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); #endif status = connect(s, (struct sockaddr*)&soc_address, sizeof(soc_address)); if (status < 0) { #ifndef DECNET /* This code is temporary backward-compatibility. It should go away when no server runs on port 2784 alone */ if (sin->sin_port == htons(TCP_PORT)) { /* Try the old one */ if (TRACE) printf ( "HTTP: Port %d doesn't answer (errno = %d). Trying good old port %d...\n", TCP_PORT, errno, OLD_TCP_PORT); sin->sin_port = htons(OLD_TCP_PORT); /* First close current socket and open a clean one */ status = NETCLOSE (s); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); status = connect(s, (struct sockaddr*)&soc_address, sizeof(soc_address)); } if (status < 0) #endif { if (TRACE) fprintf(stderr, "HTTP: Unable to connect to remote host for `%s' (errno = %d).\n", arg, errno); /* free(command); BUG OUT TBL 921121 */ return HTInetStatus("connect"); } } if (TRACE) fprintf(stderr, "HTTP connected, socket %d\n", s); /* Ask that node for the document, ** omitting the host name & anchor if not gatewayed. */ if (gate) { command = malloc(4 + strlen(arg)+ 2 + 1); if (command == NULL) outofmem(__FILE__, "HTLoadHTTP"); strcpy(command, "GET "); strcat(command, arg); } else if ( HTTP11 ) { /* not gatewayed */ /* Switch this to HTTP 1.1 */ char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION); command = malloc(4 + strlen(arg) + 11 + 6 + strlen(host) + 2 + 20 + 2 + 1); if (command == NULL) outofmem(__FILE__, "HTLoadHTTP"); strcpy(command, "GET "); strcat(command, arg); strcat(command, " HTTP/1.1\r\n"); strcat(command, "Host: "); strcat(command, host); strcat(command, "\r\n"); strcat(command, "Connection: close\r\n"); } else { char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION); command = malloc(4 + strlen(p1)+ 2 + 1); if (command == NULL) outofmem(__FILE__, "HTLoadHTTP"); strcpy(command, "GET "); strcat(command, p1); free(p1); } strcat(command, "\r\n"); /* Include CR for telnet compat. */ if (TRACE) fprintf(stderr, "HTTP writing command `%s' to socket %d\n", command, s); #ifdef NOT_ASCII { char * p; for(p = command; *p; p++) { *p = TOASCII(*p); } } #endif status = NETWRITE(s, command, (int)strlen(command)); free(command); if (status<0) { if (TRACE) fprintf(stderr, "HTTPAccess: Unable to send command.\n"); return HTInetStatus("send"); } /* Skip the HTTP 1.1 headers */ if ( HTTP11 ) { char buffer[2]; int endhdr = 0; while ( 1 ) { int rc = read(s, buffer, 1) ; if ( TRACE ) fprintf(stderr,"%c",buffer[0]); if ( rc < 1 ) { if (TRACE) fprintf(stderr, "HTTPAccess: EOF reading headers.\n"); return HTInetStatus("send"); } if ( buffer[0] == '\r' && endhdr == 0 ) endhdr = 1; else if ( buffer[0] == '\n' && endhdr == 1 ) endhdr = 2; else if ( buffer[0] == '\r' && endhdr == 2 ) endhdr = 3; else if ( buffer[0] == '\n' && endhdr == 3 ) break; else endhdr = 0; } } /* Now load the data */ { char *url = HTParse(arg, "", PARSE_ACCESS | PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION); int compressed; int fmt = diag ? WWW_PLAINTEXT : HTFileFormat (url, WWW_HTML, &compressed); HTParseFormat(fmt, (HTParentAnchor *) anAnchor, s, compressed); free (url); } if (TRACE) fprintf(stderr, "HTTP: close socket %d.\n", s); status = NETCLOSE(s); return HT_LOADED; /* Good return */ }
PUBLIC int HTLoadHTTP ARGS4 ( char *, arg, HTParentAnchor *, anAnchor, HTFormat, format_out, HTStream*, sink) { int s; /* Socket number for returned data */ char *command; /* The whole command */ char *eol; /* End of line if found */ char *start_of_data; /* Start of body of reply */ int status; /* tcp return */ int bytes_already_read; char crlf[3]; /* A CR LF equivalent string */ HTStream *target; /* Unconverted data */ HTFormat format_in; /* Format arriving in the message */ char *line_buffer; char *line_kept_clean; BOOL extensions; /* Assume good HTTP server */ int compressed; char line[2048]; /* bumped up to cover Kerb huge headers */ int length, doing_redirect, rv; int already_retrying = 0; int return_nothing; int i; int keepingalive = 0; char *p; /*SWP*/ int statusError=0; if (!arg) { status = -3; HTProgress ("Bad request."); goto done; } if (!*arg) { status = -2; HTProgress ("Bad request."); goto done; } sprintf(crlf, "%c%c", CR, LF); /* At this point, we're talking HTTP/1.0. */ extensions = YES; try_again: /* All initializations are moved down here from up above, so we can start over here... */ eol = 0; bytes_already_read = 0; length = 0; doing_redirect = 0; compressed = 0; target = NULL; line_buffer = NULL; line_kept_clean = NULL; return_nothing = 0; /* okay... addr looks like http://hagbard.ncsa.uiuc.edu/blah/etc.html lets crop it at the 3rd '/' */ for(p = arg,i=0;*p && i!=3;p++) if(*p=='/') i++; if(i==3) i = p-arg; /* i = length not counting last '/' */ else i = 0; if((lsocket != -1) && i && addr && !strncmp(addr,arg,i)){ /* keepalive is active and addresses match -- try the old socket */ s = lsocket; keepingalive = 1; /* flag in case of network error due to server timeout*/ lsocket = -1; /* prevent looping on failure */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Keep-Alive reusing '%s'\n",addr); #endif /* if (addr && *addr) { sprintf(tmpbuf,"Reusing socket from %s.",addr); HTProgress(tmpbuf); } */ } else { if(addr) free(addr); /* save the address for next time around */ addr = malloc(i+1); strncpy(addr,arg,i); *(addr+i)=0; keepingalive = 0; /* just normal opening of the socket */ if(lsocket != -1) NETCLOSE(lsocket); /* no socket leaks here */ lsocket = -1; /*dont assign until we know the server says okay */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Keep-Alive saving '%s'\n",addr); #endif /* if (addr && *addr) { sprintf(tmpbuf,"Saving %s for possible socket reuse.",addr); HTProgress(tmpbuf); } */ } if (!keepingalive) { status = HTDoConnect (arg, "HTTP", TCP_PORT, &s); if (status == HT_INTERRUPTED){ /* Interrupt cleanly. */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Interrupted on connect; recovering cleanly.\n"); #endif HTProgress ("Connection interrupted."); /* status already == HT_INTERRUPTED */ goto done; } if (status < 0) { #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTTP: Unable to connect to remote host for `%s' (errno = %d).\n", arg, errno); #endif HTProgress ("Unable to connect to remote host."); status = HT_NO_DATA; goto done; } } /* Ask that node for the document, ** omitting the host name & anchor */ { char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION); command = malloc(5 + strlen(p1)+ 2 + 31); if (do_post && !do_put) strcpy(command, "POST "); else if (do_post && do_put) strcpy(command, "PUT "); else if (do_head) strcpy(command, "HEAD "); else if (do_meta) strcpy(command, "META "); else strcpy(command, "GET "); /* * For a gateway, the beginning '/' on the request must * be stripped before appending to the gateway address. */ if ((using_gateway)||(using_proxy)) { strcat(command, p1+1); } else strcat(command, p1); free(p1); } if (extensions) { strcat(command, " "); strcat(command, HTTP_VERSION); } strcat(command, crlf); /* CR LF, as in rfc 977 */ if (extensions) { #ifdef SAM_NOT_YET /* SAM This produces an absolutely huge Accept: line. While there is probably a better way to turn this off, just compiling it out works for now. */ int n, i; if (!HTPresentations) HTFormatInit(); n = HTList_count(HTPresentations); begin_ptr=command+strlen(command); env_length=0; sprintf(line, "Accept:"); env_length+=strlen(line); StrAllocCat(command, line); /* KCMS Accept Header - swp */ if (KCMS_Return_Format==JPEG) { sprintf(line," image/x-pcd-jpeg,"); StrAllocCat(command, line); env_length+=strlen(line); } else if (KCMS_Return_Format==JYCC) { sprintf(line," image/x-pcd-jycc,"); StrAllocCat(command, line); env_length+=strlen(line); } else if (KCMS_Return_Format==GIF) { sprintf(line," image/x-pcd-gif,"); StrAllocCat(command, line); env_length+=strlen(line); } for(i=0; i<n; i++) { HTPresentation * pres = HTList_objectAt(HTPresentations, i); if (pres->rep_out == WWW_PRESENT) { sprintf(line, " %s,",HTAtom_name(pres->rep)); env_length+=strlen(line); StrAllocCat(command, line); if (env_length>200) { if ((tmp_ptr=strrchr(command,','))!=NULL) { *tmp_ptr='\0'; } sprintf(line, "%c%c",CR,LF); StrAllocCat(command, line); begin_ptr=command+strlen(command); sprintf(line, "Accept:"); env_length=strlen(line); StrAllocCat(command, line); } } } /* This gets rid of the last comma. */ if ((tmp_ptr=strrchr(command,','))!=NULL) { *tmp_ptr='\0'; sprintf(line, "%c%c",CR,LF); StrAllocCat(command, line); } else { /* No accept stuff...get rid of "Accept:" */ begin_ptr='\0'; } #endif /* if reloading, send no-cache pragma to proxy servers. --swp */ /* original patch from Ari L. <*****@*****.**> */ if (reloading) { sprintf(line, "Pragma: no-cache%c%c", CR, LF); StrAllocCat(command, line); } /*This is just used for "not" sending this header on a proxy request*/ if (useKeepAlive) { sprintf(line, "Connection: keep-alive%c%c", CR, LF); StrAllocCat(command, line); } if (sendAgent) { sprintf(line, "User-Agent: %s%c%c",agent[selectedAgent],CR,LF); /* sprintf(line, "User-Agent: %s/%s libwww/%s%c%c", HTAppName ? HTAppName : "unknown", HTAppVersion ? HTAppVersion : "0.0", HTLibraryVersion, CR, LF); */ StrAllocCat(command, line); } if (sendReferer) { /* HTTP Referer field, specifies back-link URL - amb */ if (HTReferer) { sprintf(line, "Referer: %s%c%c", HTReferer, CR, LF); StrAllocCat(command, line); HTReferer = NULL; } } { char *tmp,*startPtr,*endPtr; /* addr is always in URL form */ if (addr && !using_proxy && !using_gateway) { tmp=strdup(addr); startPtr=strchr(tmp,'/'); if (startPtr) { startPtr+=2; /*now at begining of hostname*/ if (*startPtr) { endPtr=strchr(startPtr,':'); if (!endPtr) { endPtr=strchr(startPtr,'/'); if (endPtr && *endPtr) { *endPtr='\0'; } } else { *endPtr='\0'; } sprintf(line, "Host: %s%c%c", startPtr, CR, LF); StrAllocCat(command, line); free(tmp); tmp=startPtr=endPtr=NULL; } } } else if (using_proxy || using_gateway) { sprintf(line, "Host: %s%c%c", proxy_host_fix, CR, LF); StrAllocCat(command, line); } } /* SWP -- 7/10/95 */ /* HTTP Extension headers */ /* Domain Restriction */ sprintf(line,"Extension: Notify-Domain-Restriction%c%c",CR,LF); StrAllocCat(command,line); /* BJS -- 12/05/95 -- allow arbitrary headers sent from browser */ if(extra_headers){ int h; for(h=0;extra_headers[h];h++){ sprintf(line,"%s%c%c",extra_headers[h],CR,LF); StrAllocCat(command,line); } } { char *docname; char *hostname; char *colon; int portnumber; char *auth; docname = HTParse(arg, "", PARSE_PATH); hostname = HTParse(arg, "", PARSE_HOST); if (hostname && NULL != (colon = strchr(hostname, ':'))) { *(colon++) = '\0'; /* Chop off port number */ portnumber = atoi(colon); } else portnumber = 80; if (NULL!=(auth=HTAA_composeAuth(hostname, portnumber, docname))) { sprintf(line, "%s%c%c", auth, CR, LF); StrAllocCat(command, line); } #ifndef DISABLE_TRACE if (www2Trace) { if (auth) fprintf(stderr, "HTTP: Sending authorization: %s\n", auth); else fprintf(stderr, "HTTP: Not sending authorization (yet)\n"); } #endif FREE(hostname); FREE(docname); } } if (do_post && !do_put) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Doing post, content-type '%s'\n", post_content_type); #endif sprintf (line, "Content-type: %s%c%c", post_content_type ? post_content_type : "lose", CR, LF); StrAllocCat(command, line); { int content_length; if (!post_data) content_length = 4; /* 4 == "lose" :-) */ else content_length = strlen (post_data); sprintf (line, "Content-length: %d%c%c", content_length, CR, LF); StrAllocCat(command, line); } StrAllocCat(command, crlf); /* Blank line means "end" */ if (post_data) StrAllocCat(command, post_data); else StrAllocCat(command, "lose"); } else if (do_post && do_put) { sprintf (line, "Content-length: %d%c%c", put_file_size, CR, LF); StrAllocCat(command, line); StrAllocCat(command, crlf); /* Blank line means "end" */ } else { StrAllocCat(command, crlf); /* Blank line means "end" */ } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "Writing:\n%s----------------------------------\n", command); #endif /* HTProgress ("Sending HTTP request."); */ status = NETWRITE(s, command, (int)strlen(command)); if (do_post && do_put) { char buf[BUFSIZ]; int upcnt=0,n; while (status>0) { n=fread(buf,1,BUFSIZ-1,put_fp); upcnt+= status = NETWRITE(s, buf, n); #ifndef DISABLE_TRACE if (www2Trace) { fprintf(stderr,"[%d](%d) %s",status,n,buf); } #endif if (feof(put_fp)) { break; } } if (status<0 || !feof(put_fp) || upcnt!=put_file_size) { char tmpbuf[BUFSIZ]; sprintf(tmpbuf,"Status: %d -- EOF: %d -- UpCnt/FileSize: %d/%d\n\nThe server you connected to either does not support\nthe PUT method, or an error occurred.\n\nYour upload was corrupted! Please try again!",status,(feof(put_fp)?1:0),upcnt,put_file_size); application_error(tmpbuf,"Upload Error!"); } } /* Twirl on each request to make things look nicer -- SWP */ HTCheckActiveIcon(1); #ifndef DISABLE_TRACE if (httpTrace) { fprintf(stderr,"%s",command); } #endif free (command); if (status <= 0) { if (status == 0) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Got status 0 in initial write\n"); #endif /* Do nothing. */ } else if ((errno == ENOTCONN || errno == ECONNRESET || errno == EPIPE) && !already_retrying && /* Don't retry if we're posting. */ !do_post) { /* Arrrrgh, HTTP 0/1 compability problem, maybe. */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: BONZO ON WRITE Trying again with HTTP0 request.\n"); #endif /* HTProgress ("Retrying as HTTP0 request."); */ NETCLOSE(s); // SAM extensions = NO; already_retrying = 1; goto try_again; } else { if(keepingalive){ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Timeout on Keep-Alive. Retrying.\n"); #endif HTProgress("Server Timeout: Reconnecting"); goto try_again; } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Hit unexpected network WRITE error; aborting connection.\n"); #endif NETCLOSE (s); status = -1; HTProgress ("Unexpected network write error; connection aborted."); goto done; } } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: WRITE delivered OK\n"); #endif HTProgress ("Done sending HTTP request; waiting for response."); /* Read the first line of the response ** ----------------------------------- */ { /* Get numeric status etc */ BOOL end_of_file = NO; int buffer_length = INIT_LINE_SIZE; line_buffer = (char *) malloc(buffer_length * sizeof(char)); do { /* Loop to read in the first line */ /* Extend line buffer if necessary for those crazy WAIS URLs ;-) */ if (buffer_length - length < LINE_EXTEND_THRESH) { buffer_length = buffer_length + buffer_length; line_buffer = (char *) realloc(line_buffer, buffer_length * sizeof(char)); } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Trying to read %d\n", buffer_length - length - 1); #endif status = NETREAD(s, line_buffer + length, buffer_length - length - 1); #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Read %d\n", status); #endif if (status <= 0) { /* Retry if we get nothing back too; bomb out if we get nothing twice. */ if (status == HT_INTERRUPTED) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Interrupted initial read.\n"); #endif HTProgress ("Connection interrupted."); status = HT_INTERRUPTED; NETCLOSE (s); goto clean_up; } else if (status < 0 && (errno == ENOTCONN || errno == ECONNRESET || errno == EPIPE) && !already_retrying && !do_post) { /* Arrrrgh, HTTP 0/1 compability problem, maybe. */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: BONZO Trying again with HTTP0 request.\n"); #endif NETCLOSE(s); if (line_buffer) free(line_buffer); if (line_kept_clean) free(line_kept_clean); extensions = NO; already_retrying = 1; HTProgress ("Retrying as HTTP0 request."); goto try_again; } else { if(keepingalive){ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Timeout on Keep-Alive. Retrying.\n"); #endif HTProgress("Server Timeout: Reconnecting"); goto try_again; } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Hit unexpected network read error; aborting connection; status %d.\n", status); #endif HTProgress ("Unexpected network read error; connection aborted."); NETCLOSE (s); status = -1; goto clean_up; } } bytes_already_read += status; { char line[256]; sprintf (line, "Read %d bytes of data.", bytes_already_read); HTProgress (line); } if (status == 0) { end_of_file = YES; break; } line_buffer[length+status] = 0; if (line_buffer) { if (line_kept_clean) free (line_kept_clean); line_kept_clean = (char *)malloc (buffer_length * sizeof (char)); /* bcopy (line_buffer, line_kept_clean, buffer_length); */ memcpy (line_kept_clean, line_buffer, buffer_length); } eol = strchr(line_buffer + length, LF); /* Do we *really* want to do this? */ if (eol && eol != line_buffer && *(eol-1) == CR) *(eol-1) = ' '; length = length + status; /* Do we really want to do *this*? */ if (eol) *eol = 0; /* Terminate the line */ /* All we need is the first line of the response. If it's a HTTP/1.0 response, then the first line will be absurdly short and therefore we can safely gate the number of bytes read through this code (as opposed to below) to ~1000. */ /* Well, let's try 100. */ } while (!eol && !end_of_file && bytes_already_read < 100); } /* Scope of loop variables */ /* We now have a terminated unfolded line. Parse it. ** ------------------------------------------------- */ #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTTP: Rx: %s\n", line_buffer); #endif { int fields; char server_version[VERSION_LENGTH+1]; int server_status; /*SWP*/ statusError=0; server_version[0] = 0; fields = sscanf(line_buffer, "%20s %d", server_version, &server_status); #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Scanned %d fields from line_buffer\n", fields); #endif #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: line_buffer '%s'\n", line_buffer); #endif /* Rule out HTTP/1.0 reply as best we can. */ if (fields < 2 || !server_version[0] || server_version[0] != 'H' || server_version[1] != 'T' || server_version[2] != 'T' || server_version[3] != 'P' || server_version[4] != '/' || server_version[6] != '.') { /* HTTP0 reply */ HTAtom * encoding; #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "--- Talking HTTP0.\n"); #endif format_in = HTFileFormat(arg, &encoding, WWW_HTML, &compressed); start_of_data = line_kept_clean; } else { /* Decode full HTTP response */ format_in = HTAtom_for("www/mime"); /* We set start_of_data to "" when !eol here because there will be a put_block done below; we do *not* use the value of start_of_data (as a pointer) in the computation of length or anything else in this situation. */ start_of_data = eol ? eol + 1 : ""; length = eol ? length - (start_of_data - line_buffer) : 0; #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "--- Talking HTTP1.\n"); #endif switch (server_status / 100) { case 3: /* Various forms of redirection */ /* We now support this in the parser, at least. */ doing_redirect = 1; break; case 4: /* "I think I goofed" */ switch (server_status) { case 403: statusError=1; /* 403 is "forbidden"; display returned text. */ break; case 401: /* length -= start_of_data - text_buffer; */ if (HTAA_shouldRetryWithAuth(start_of_data, length, s)) { (void)NETCLOSE(s); lsocket = -1; if (line_buffer) free(line_buffer); if (line_kept_clean) free(line_kept_clean); #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "%s %d %s\n", "HTTP: close socket", s, "to retry with Access Authorization"); #endif HTProgress ("Retrying with access authorization information."); goto try_again; break; } else { statusError=1; /* Fall through. */ } default: statusError=1; break; } /* case 4 switch */ break; case 5: /* I think you goofed */ statusError=1; break; case 2: /* Good: Got MIME object */ switch (server_status) { case 204: return_nothing = 1; format_in = HTAtom_for("text/html"); break; case 200: if (do_head) { if (!start_of_data || !*start_of_data) { headData=NULL; } else { char *ptr; headData=strdup(start_of_data); ptr=strchr(headData,'\n'); *ptr='\0'; } } break; default: break; } break; default: /* bad number */ statusError=1; HTAlert("Unknown status reply from server!"); break; } /* Switch on server_status/100 */ } /* Full HTTP reply */ } /* scope of fields */ /* Set up the stream stack to handle the body of the message */ target = HTStreamStack(format_in, format_out, compressed, sink, anAnchor); if (!target) { char buffer[1024]; /* @@@@@@@@ */ sprintf(buffer, "Sorry, no known way of converting %s to %s.", HTAtom_name(format_in), HTAtom_name(format_out)); HTProgress (buffer); status = -1; NETCLOSE (s); lsocket = -1; goto clean_up; } if (!return_nothing) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Doing put_block, '%s'\n", start_of_data); #endif /* BJS: parse start_of_data...*/ for(p=start_of_data;*p;p++){ /* if(*p=='C' && !strncmp("Content-length: ",p,16)){ i = 0; p+=16; while(*p && isdigit(*p)){ i = i*10 + *p-'0'; p++; } p--; #ifndef DISABLE_TRACE if(www2Trace) fprintf(stderr, "HTTP: Content Length is %d\n",i); #endif } */ if(*p=='K' && !strncmp("Keep-Alive:",p,11)){ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Server Agrees to Keep-Alive\n"); #endif lsocket = s; p+=10; } } #ifndef DISABLE_TRACE if (www2Trace && lsocket == -1) fprintf (stderr, "HTTP: Server does not agree to Keep-Alive\n"); #endif /* Recycle the first chunk of data, in all cases. */ (*target->isa->put_block)(target, start_of_data, length); /* Go pull the bulk of the data down. */ /* if we dont use length, header length is wrong due to the discarded first line - bjs*/ rv = HTCopy(s, target, length /*bytes_already_read*/); if (rv == -1) { (*target->isa->handle_interrupt) (target); status = HT_INTERRUPTED; NETCLOSE (s); lsocket = -1; goto clean_up; } if (rv == -2 && !already_retrying && !do_post) { /* Aw hell. */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Trying again with HTTP0 request.\n"); #endif /* May as well consider it an interrupt -- right? */ (*target->isa->handle_interrupt) (target); NETCLOSE(s); if (line_buffer) free(line_buffer); if (line_kept_clean) free(line_kept_clean); extensions = NO; already_retrying = 1; HTProgress ("Retrying as HTTP0 request."); goto try_again; } } else { /* return_nothing is high. */ (*target->isa->put_string) (target, "<mosaic-access-override>\n"); HTProgress ("And silence filled the night."); } (*target->isa->end_document)(target); /* Close socket before doing free. */ if(lsocket == -1){ NETCLOSE(s); #ifndef DISABLE_TRACE if(www2Trace) fprintf(stderr,"HTTP: Closing connection\n"); #endif } else { HTProgress("Leaving Server Connection Open"); #ifndef DISABLE_TRACE if(www2Trace) fprintf(stderr,"HTTP: Keeping connection alive\n"); #endif } /* else { NETCLOSE(s); #ifndef DISABLE_TRACE if(www2Trace) fprintf(stderr,"HTTP: Closing connection\n"); #endif } */ (*target->isa->free)(target); if (doing_redirect) { /* OK, now we've got the redirection URL temporarily stored in external variable redirecting_url, exported from HTMIME.c, since there's no straightforward way to do this in the library currently. Do the right thing. */ status = HT_REDIRECTING; } else { status = HT_LOADED; } /* Clean up */ clean_up: if (line_buffer) free(line_buffer); if (line_kept_clean) free(line_kept_clean); done: /* Clear out on exit, just in case. */ do_post = 0; if (statusError) { securityType=HTAA_NONE; #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr,"Resetting security type to NONE.\n"); #endif } return status; }