BinURLInputStream::BinURLInputStream(const XMLURL& urlSource) : fBuffer(0) , fBufferSize(0) , fBufferIndex(0) , fRemoteFileSize(0) , fAnchor(0) , fBytesProcessed(0) , fMemoryManager(urlSource.getMemoryManager()) { fBuffer = (XMLByte*) fMemoryManager->allocate ( URLISBUFMAXSIZE * sizeof(XMLByte) );//new XMLByte[URLISBUFMAXSIZE]; const XMLCh* uri = urlSource.getURLText(); char* uriAsCharStar = localTranscode(uri, fMemoryManager); // // First find the size of the remote resource being asked for. // We use the ContentCounter stream provided by libWWW. // fAnchor = HTAnchor_findAddress(uriAsCharStar); HTRequest* request = HTRequest_new(); HTRequest_setOutputFormat(request, WWW_SOURCE); HTStream* counterStrm = HTContentCounter(HTBlackHole(), request, 0xFFFF); BOOL status = HTLoadToStream(uriAsCharStar, counterStrm, request); if (status == YES) { HTParentAnchor * anchor = HTRequest_anchor(request); fRemoteFileSize=HTAnchor_length(anchor); if(fRemoteFileSize < 0) { // Patch by Artur Klauser // When a redirection is processed in libWWW, it seems that // HTAnchor_length(anchor) == -1 on the original anchor, whereas // HTResponse_length(response) gives the correct content length of // the redirection target. This has confused fRemoteFileSize and it was // not checked for a -1 response at all. HTResponse * response = HTRequest_response (request); fRemoteFileSize = HTResponse_length(response); if (fRemoteFileSize < 0) { ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_LengthError, fMemoryManager); } } } // Cleanup, before you throw any errors. fMemoryManager->deallocate(uriAsCharStar); HTRequest_delete(request); // Don't know whether I am supposed to delete counterStrm. if (status == NO) { ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_LengthError, fMemoryManager); } }
/* Create a new coder and insert it into stream chain ** -------------------------------------------------- ** Creating the content decoding stack is not based on quality factors as ** we don't have the freedom as with content types. Specify whether you ** you want encoding or decoding using the BOOL "encode" flag. */ PUBLIC HTStream * HTContentCodingStack (HTEncoding encoding, HTStream * target, HTRequest * request, void * param, BOOL encode) { HTList * coders[2]; HTStream * top = target; HTCoding * pres = NULL; HTCoding * best_match = NULL; double best_quality = -1e30; /* Pretty bad! */ int cnt; if (!encoding || !request) { HTTRACE(CORE_TRACE, "Codings... Nothing applied...\n"); return target ? target : HTErrorStream(); } coders[0] = HTRequest_encoding(request); coders[1] = HTContentCoders; HTTRACE(CORE_TRACE, "C-E......... Looking for `%s\'\n" _ HTAtom_name(encoding)); for (cnt=0; cnt < 2; cnt++) { HTList * cur = coders[cnt]; while ((pres = (HTCoding *) HTList_nextObject(cur))) { if ((pres->encoding == encoding || HTMIMEMatch(pres->encoding, encoding)) && pres->quality > best_quality) { best_match = pres; best_quality = pres->quality; } } } if (best_match) { HTTRACE(CORE_TRACE, "C-E......... Found `%s\'\n" _ HTAtom_name(best_match->encoding)); if (encode) { if (best_match->encoder) top = (*best_match->encoder)(request, param, encoding, top); } else { if (best_match->decoder) top = (*best_match->decoder)(request, param, encoding, top); } } else if (!HTFormat_isUnityContent(encoding)) { /* ** If this is not a unity coding and we didn't find any coders ** that could handle it then put in a local file save stream ** instead of the stream that we got. */ if (encode) { HTTRACE(CORE_TRACE, "C-E......... NOT FOUND - can't encode stream!\n"); } else { HTTRACE(CORE_TRACE, "C-E......... NOT FOUND - error!\n"); top = HTBlackHole(); } } return top; }
/* Create a new transfer coder and insert it into stream chain ** ----------------------------------------------------------- ** Creating the content decoding stack is not based on quality factors as ** we don't have the freedom as with content types. Specify whether you ** you want encoding or decoding using the BOOL "encode" flag. */ PUBLIC HTStream * HTContentTransferCodingStack (HTEncoding encoding, HTStream * target, HTRequest * request, void * param, BOOL encode) { HTList * coders[2]; HTStream * top = target; HTCoding * pres = NULL; int cnt; if (!encoding || !request) { HTTRACE(CORE_TRACE, "C-T-E..... Nothing applied...\n"); return target ? target : HTErrorStream(); } /* ** We use the same encoders/decoders as for Transfer-Encodings */ coders[0] = HTRequest_transfer(request); coders[1] = HTTransferCoders; HTTRACE(CORE_TRACE, "C-T-E....... Looking for %s\n" _ HTAtom_name(encoding)); for (cnt=0; cnt < 2; cnt++) { HTList * cur = coders[cnt]; while ((pres = (HTCoding *) HTList_nextObject(cur))) { if (pres->encoding == encoding) { HTTRACE(CORE_TRACE, "C-T-E....... Found...\n"); if (encode) { if (pres->encoder) top = (*pres->encoder)(request, param, encoding, top); break; } else if (pres->decoder) { top = (*pres->decoder)(request, param, encoding, top); break; } } } } /* ** If this is not a unity coding and we didn't find any coders ** that could handle it then put in a local file save stream ** instead of the stream that we got. */ if (!HTFormat_isUnityTransfer(encoding) && target==top) { if (encode) { HTTRACE(CORE_TRACE, "C-T-E....... NOT FOUND - removing encoding!\n"); HTAnchor_setContentTransferEncoding(HTRequest_anchor(request), NULL); } else { HTTRACE(CORE_TRACE, "C-T-E....... NOT FOUND - error!\n"); top = HTBlackHole(); } } return top; }
/* ** Here you can provide a complete list instead of a single token. ** The list has to filled up in the order the _encodings_ are to be applied */ PUBLIC HTStream * HTTransferEncodingStack (HTList * encodings, HTStream * target, HTRequest * request, void * param) { if (encodings) { HTList * cur = encodings; HTEncoding pres; HTStream * top = target; while ((pres = (HTEncoding) HTList_nextObject(cur))) { top = HTTransferCodingStack(pres, top, request, param, YES); if (top == HTBlackHole()) break; } return top; } return HTErrorStream(); }
/* ** Here you can provide a complete list instead of a single token. ** The list has to be in the order the _encodings_ were applied - that ** is, the same way that _encodings_ are to be applied. This is all consistent ** with the order of the Content-Encoding header. */ PUBLIC HTStream * HTTransferDecodingStack (HTList * encodings, HTStream * target, HTRequest * request, void * param) { if (encodings) { HTEncoding pres; int cnt = HTList_count(encodings); HTStream * top = target; while (cnt > 0) { pres = (HTEncoding) HTList_objectAt(encodings, --cnt); top = HTTransferCodingStack(pres, top, request, param, NO); if (top == HTBlackHole()) break; } return top; } return HTErrorStream(); }
/* Take action using a system command ** ---------------------------------- ** ** Creates temporary file, writes to it, executes system command ** on end-document. The suffix of the temp file can be given ** in case the application is fussy, or so that a generic opener can ** be used. */ PUBLIC HTStream* HTSaveAndExecute ARGS5( HTRequest *, request, void *, param, HTFormat, input_format, HTFormat, output_format, HTStream *, output_stream) #ifdef unix #define REMOVE_FILE unlink #endif #ifdef VMS #define REMOVE_FILE unlink /* ok? */ #endif #ifdef REMOVE_FILE { char *fnam, *physical; HTStream* me; if (HTSecure) { HTAlert("Can't save data to file -- please run WWW locally"); return HTBlackHole(); } if (!HTSaveLocallyDir) { if (TRACE) fprintf(stderr, "Save and execute turned off"); return HTBlackHole(); } me = (HTStream*)calloc(sizeof(*me),1); me = (HTStream*)calloc(sizeof(*me), 1); if (me == NULL) outofmem(__FILE__, "Save and execute"); me->isa = &HTFWriter; /* Let's find a hash name for this file */ physical = HTAnchor_physical(request->anchor); if ( !physical ) physical = request->anchor->address; if ((fnam = HTFWriter_filename(HTSaveLocallyDir, physical, HTFileSuffix(input_format), 1000)) == NULL) { HTAlert("Can't find a suitable file name"); return NULL; } me->request = request; /* won't be freed */ me->fp = fopen (fnam, "w"); if (!me->fp) { HTAlert("Can't open temporary file!"); free(fnam); free(me); return NULL; } StrAllocCopy(me->filename, fnam); /* Make command to process file */ me->end_command = (char *)malloc ( (strlen (param) + 10+ 3*strlen(fnam)) * sizeof (char)); if (me == NULL) outofmem(__FILE__, "SaveAndExecute"); sprintf (me->end_command, param, fnam, fnam, fnam); me->remove_on_close = NO; me->announce = NO; free (fnam); return me; }
PRIVATE int pumpData (HTStream * me) { HTRequest * request = me->request; HTResponse * response = me->response; HTFormat format = HTResponse_format(response); HTList * te = HTResponse_transfer(response); HTList * ce = HTResponse_encoding(response); long length = HTResponse_length(response); HTStream * BlackHole = HTBlackHole(); BOOL savestream = NO; me->transparent = YES; /* Pump rest of data right through */ /* ** Cache the metainformation in the anchor object by copying ** it from the response object. This we do regardless if ** we have a persistent cache or not as the memory cache will ** use it as well. If we are updating a cache entry using ** byte ranges then we already have the metainformation and ** hence we can ignore the new one as it'd better be the same. */ if (!(me->mode & HT_MIME_PARTIAL) && HTResponse_isCachable(me->response) != HT_NO_CACHE) HTAnchor_update(HTRequest_anchor(request), me->response); /* ** If we asked only to read the header or footer or we used a HEAD ** method then we stop here as we don't expect any body part. */ if (me->mode & (HT_MIME_HEADER | HT_MIME_FOOTER) || HTRequest_method(request) == METHOD_HEAD) { HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE); if (cbf) (*cbf)(request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL); return HT_LOADED; } /* ** If we are paring a 1xx response then return HT_CONTINUE */ if (me->mode & HT_MIME_CONT) return HT_CONTINUE; /* ** If we get a 101 Protocol Switch then we are done here ** but not done with the response (which we don't know ** how to go about parsing */ if (me->mode & HT_MIME_UPGRADE) { me->hasBody = YES; return HT_OK; } /* ** If there is no content-length, no transfer encoding and no ** content type then we assume that there is no body part in ** the message and we can return HT_LOADED */ { HTHost * host = HTNet_host(me->net); if (length<0 && te==NULL && HTHost_isPersistent(host) && !HTHost_closeNotification(host)) { if (format != WWW_UNKNOWN) { HTTRACE(STREAM_TRACE, "MIME Parser. BAD - there seems to be a body but no length. This must be an HTTP/1.0 server pretending that it is HTTP/1.1\n"); HTHost_setCloseNotification(host, YES); } else { HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE); if (cbf) (*cbf)(request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL); HTTRACE(STREAM_TRACE, "MIME Parser. No body in this message\n"); return HT_LOADED; } } } /* ** Deal with the body */ me->hasBody = YES; /* ** Handle any Content Type */ if (!(me->mode & HT_MIME_PARTIAL) && (format != WWW_UNKNOWN || length > 0 || te)) { HTStream * target; HTTRACE(STREAM_TRACE, "Building.... C-T stack from %s to %s\n" _ HTAtom_name(format) _ HTAtom_name(me->target_format)); if ((target = HTStreamStack(format, me->target_format, me->target, request, YES))==BlackHole) { if (!savestream) { if (me->target) (*me->target->isa->abort)(me->target, NULL); me->target = me->save_stream(request, NULL, format, me->target_format, me->target); savestream = YES; } } else me->target = target; } /* ** Handle any Content Encodings */ HTTRACE(STREAM_TRACE, "Building.... Content-Decoding stack\n"); if (ce) { HTStream * target = HTContentDecodingStack(ce, me->target, request, NULL); if (target == BlackHole) { if (!savestream) { if (me->target) (*me->target->isa->abort)(me->target, NULL); me->target = me->save_stream(request, NULL, format, me->target_format, me->target); savestream = YES; } } else me->target = target; } /* ** Can we cache the data object? If so then create a T stream and hook it ** into the stream pipe. We do it before the transfer decoding so that we ** don't have to deal with that when we retrieve the object from cache. ** If we are appending to a cache entry then use a different stream than ** if creating a new entry. */ #ifndef NO_CACHE if (HTCacheMode_enabled()) { if (me->mode & HT_MIME_PARTIAL) { HTStream * append = HTStreamStack(WWW_CACHE_APPEND, me->target_format, me->target, request, NO); if (append) me->target = HTTee(me->target, append, NULL); #if 0 /* @@ JK: change */ if (append) me->target = append; #endif } else if (HTResponse_isCachable(me->response) == HT_CACHE_ALL) { HTStream * cache = HTStreamStack(WWW_CACHE, me->target_format, me->target, request, NO); if (cache) me->target = HTTee(me->target, cache, NULL); } } #endif /* ** Handle any Transfer Encodings */ HTTRACE(STREAM_TRACE, "Building.... Transfer-Decoding stack\n"); if (te) { HTStream * target = HTTransferDecodingStack(te, me->target, request, NULL); if (target == BlackHole) { if (!savestream) { if (me->target) (*me->target->isa->abort)(me->target, NULL); me->target = me->save_stream(request, NULL, format, me->target_format, me->target); savestream = YES; } } else me->target = target; } /* ** If we for some reason couldn't find a target stream */ if (!me->target) me->target = HTBlackHole(); return HT_OK; }
/* Take action using a system command ** ---------------------------------- ** ** originally from Ghostview handling by Marc Andreseen. ** Creates temporary file, writes to it, executes system command ** on end-document. The suffix of the temp file can be given ** in case the application is fussy, or so that a generic opener can ** be used. */ PUBLIC HTStream* HTSaveAndExecute ARGS3( HTPresentation *, pres, HTParentAnchor *, anchor, /* Not used */ HTStream *, sink) /* Not used */ #ifdef UNIX #define REMOVE_COMMAND "/bin/rm -f %s\n" #endif #ifdef VMS #define REMOVE_COMMAND "delete/noconfirm/nolog %s.." #endif #ifdef REMOVE_COMMAND { char *fnam; CONST char * suffix; HTStream* me; if (HTClientHost) { HTAlert(CANNOT_SAVE_REMOTE); return HTBlackHole(); } me = (HTStream*)malloc(sizeof(*me)); if (me == NULL) outofmem(__FILE__, "Save and execute"); me->isa = &HTFWriter; /* Save the file under a suitably suffixed name */ suffix = HTFileSuffix(pres->rep, anchor->content_encoding); fnam = (char *)malloc (L_tmpnam + 16 + strlen(suffix)); if (fnam == NULL) outofmem(__FILE__, "HTSaveAndExecute"); tmpnam (fnam); strcat(fnam, suffix); me->fp = fopen (fnam, BIN_W); if (!me->fp) { HTAlert(CANNOT_OPEN_TEMP); FREE(fnam); FREE(me); return NULL; } /* Make command to process file */ me->end_command = 0; HTSprintf0(&(me->end_command), pres->command, fnam, fnam, fnam); me->remove_command = NULL; /* If needed, put into end_command */ #ifdef NOPE /* Make command to delete file */ me->remove_command = 0; HTSprintf0(&(me->remove_command), REMOVE_COMMAND, fnam); #endif me->announce = NO; FREE(fnam); return me; }
/* Save Locally ** ------------ ** Saves a file to local disk. This can for example be used to dump ** data objects of unknown media types to local disk. The stream prompts ** for a file name for the temporary file. */ PUBLIC HTStream* HTSaveLocally (HTRequest * request, void * param, HTFormat input_format, HTFormat output_format, HTStream * output_stream) { FILE * fp = NULL; char * filename = NULL; HTUserProfile * up = HTRequest_userProfile(request); char * tmproot = HTUserProfile_tmp(up); if (HTLib_secure()) { HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED, NULL, 0, "HTSaveLocally"); return HTErrorStream(); } if (!tmproot) { HTTRACE(STREAM_TRACE, "Save File... turned off\n"); return HTErrorStream(); } /* Let's prompt the user for a file name for this file */ { HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT); HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request); /* ** If we found an alert handler for prompting the user then call it. ** If not then either we are in non-interactive mode or no handler ** has been registered. For now we then return a blackhole which may ** not be the best thing to do. */ if (cbf) { HTAlertPar * reply = HTAlert_newReply(); char * suffix = HTBind_getSuffix(anchor); char * deflt = get_filename(tmproot, HTAnchor_physical(anchor), suffix, YES); if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply)) filename = HTAlert_replyMessage(reply); HTAlert_deleteReply(reply); HT_FREE(suffix); HT_FREE(deflt); } if (filename) { if ((fp = fopen(filename, "wb")) == NULL) { HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE, filename, strlen(filename),"HTSaveLocally"); HT_FREE(filename); return HTErrorStream(); } } else if (cbf) { HTTRACE(STREAM_TRACE, "Save File... No file name - error stream\n"); return HTErrorStream(); } else { HTTRACE(STREAM_TRACE, "Save File... No file name - black hole\n"); return HTBlackHole(); } } /* Now we are ready for creating the file writer stream */ if (fp) { HTStream * me = HTFileSave_new(request, fp, NO); me->filename = filename; return me; } HT_FREE(filename); return HTErrorStream(); }
int main (int argc, char ** argv) { int status = 0; int arg; int tokencount = 0; BOOL formdata = NO; HTChunk * keywords = NULL; /* From command line */ HTAssocList*formfields = NULL; HTMethod method = METHOD_GET; /* Default value */ ComLine * cl = ComLine_new(); BOOL cache = NO; /* Use persistent cache */ BOOL flush = NO; /* flush the persistent cache */ char * cache_root = NULL; /* Starts Mac GUSI socket library */ #ifdef GUSI GUSISetup(GUSIwithSIOUXSockets); GUSISetup(GUSIwithInternetSockets); #endif #ifdef __MWERKS__ /* STR */ InitGraf((Ptr) &qd.thePort); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(nil); InitCursor(); SIOUXSettings.asktosaveonclose = false; argc=ccommand(&argv); #endif /* Initiate W3C Reference Library with a client profile */ HTProfile_newNoCacheClient(APP_NAME, APP_VERSION); /* Need our own trace and print functions */ HTPrint_setCallback(printer); HTTrace_setCallback(tracer); /* ** Delete the default Username/password handler so that we can handle ** parameters handed to us from the command line. The default is set ** by the profile. */ HTAlert_deleteOpcode(HT_A_USER_PW); HTAlert_add(PromptUsernameAndPassword, HT_A_USER_PW); /* ** Add default content decoder. We insert a through line as it doesn't ** matter that we get an encoding that we don't know. */ HTFormat_addCoding("*", HTIdentityCoding, HTIdentityCoding, 0.3); /* Scan command Line for parameters */ for (arg=1; arg<argc; arg++) { if (*argv[arg] == '-') { /* - alone => filter */ if (argv[arg][1] == '\0') { cl->flags |= CL_FILTER; /* -? or -help: show the command line help page */ } else if (!strcmp(argv[arg],"-?") || !strcmp(argv[arg],"-help")) { cl->anchor = (HTParentAnchor *) HTAnchor_findAddress(W3C_HELP); tokencount = 1; /* non-interactive */ } else if (!strcmp(argv[arg], "-n")) { HTAlert_setInteractive(NO); /* Treat the keywords as form data with a <name> "=" <value> */ } else if (!strcmp(argv[arg], "-form")) { formdata = YES; /* from -- Initial represntation (only with filter) */ } else if (!strcmp(argv[arg], "-from")) { cl->format = (arg+1 < argc && *argv[arg+1] != '-') ? HTAtom_for(argv[++arg]) : WWW_HTML; /* to -- Final representation */ } else if (!strcmp(argv[arg], "-to")) { HTFormat format = (arg+1 < argc && *argv[arg+1] != '-') ? HTAtom_for(argv[++arg]) : DEFAULT_FORMAT; HTRequest_setOutputFormat(cl->request, format); /* destination for PUT, POST etc. */ } else if (!strcmp(argv[arg], "-dest")) { if (arg+1 < argc && *argv[arg+1] != '-') { char * dest = HTParse(argv[++arg], cl->cwd, PARSE_ALL); cl->dest = (HTParentAnchor *) HTAnchor_findAddress(dest); HT_FREE(dest); } /* source please */ } else if (!strcmp(argv[arg], "-source")) { HTRequest_setOutputFormat(cl->request, WWW_RAW); /* log file */ } else if (!strcmp(argv[arg], "-l")) { cl->logfile = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_LOG_FILE; /* Max forward hops in case of TRACE request */ } else if (!strcmp(argv[arg], "-hops") || !strcmp(argv[arg], "-maxforwards")) { int hops = (arg+1 < argc && *argv[arg+1] != '-') ? atoi(argv[++arg]) : DEFAULT_HOPS; if (hops >= 0) HTRequest_setMaxForwards(cl->request, hops); /* automated authentication of format user:password@realm */ } else if (!strncmp(argv[arg], "-auth", 5)) { char * credentials = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : NULL; if (credentials) ParseCredentials(cl, credentials); /* rule file */ } else if (!strcmp(argv[arg], "-r")) { cl->rules = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_RULE_FILE; /* output filename */ } else if (!strcmp(argv[arg], "-o")) { cl->outputfile = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_OUTPUT_FILE; /* timeout -- Change the default request timeout */ } else if (!strcmp(argv[arg], "-timeout")) { int timeout = (arg+1 < argc && *argv[arg+1] != '-') ? atoi(argv[++arg]) : DEFAULT_TIMEOUT; if (timeout >= 1) cl->timer = timeout*MILLIES; /* preemptive or non-preemptive access */ } else if (!strcmp(argv[arg], "-single")) { HTRequest_setPreemptive(cl->request, YES); /* content Length Counter */ } else if (!strcmp(argv[arg], "-cl")) { cl->flags |= CL_COUNT; /* print version and exit */ } else if (!strcmp(argv[arg], "-version")) { VersionInfo(argv[0]); Cleanup(cl, 0); /* run in quiet mode */ } else if (!strcmp(argv[arg], "-q")) { cl->flags |= CL_QUIET; /* Start the persistent cache */ } else if (!strcmp(argv[arg], "-cache")) { cache = YES; /* Determine the cache root */ } else if (!strcmp(argv[arg], "-cacheroot")) { cache_root = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : NULL; /* Persistent cache flush */ } else if (!strcmp(argv[arg], "-flush")) { flush = YES; /* Do a cache validation */ } else if (!strcmp(argv[arg], "-validate")) { cl->flags |= CL_VALIDATE; /* Do an end-to-end cache-validation */ } else if (!strcmp(argv[arg], "-endvalidate")) { cl->flags |= CL_END_VALIDATE; /* Force complete reload */ } else if (!strcmp(argv[arg], "-nocache")) { cl->flags |= CL_CACHE_FLUSH; #ifdef WWWTRACE /* trace flags */ } else if (!strncmp(argv[arg], "-v", 2)) { HTSetTraceMessageMask(argv[arg]+2); #endif /* GET method */ } else if (!strcasecomp(argv[arg], "-get")) { method = METHOD_GET; /* HEAD method */ } else if (!strcasecomp(argv[arg], "-head")) { method = METHOD_HEAD; /* DELETE method */ } else if (!strcasecomp(argv[arg], "-delete")) { method = METHOD_DELETE; /* POST Method */ } else if (!strcasecomp(argv[arg], "-post")) { method = METHOD_POST; /* PUT Method */ } else if (!strcasecomp(argv[arg], "-put")) { method = METHOD_PUT; /* OPTIONS Method */ } else if (!strcasecomp(argv[arg], "-options")) { method = METHOD_OPTIONS; /* TRACE Method */ } else if (!strcasecomp(argv[arg], "-trace")) { method = METHOD_TRACE; } else { if (SHOW_MSG) HTPrint("Bad Argument (%s)\n", argv[arg]); } } else { /* If no leading `-' then check for URL or keywords */ if (!tokencount) { char * ref = HTParse(argv[arg], cl->cwd, PARSE_ALL); cl->anchor = (HTParentAnchor *) HTAnchor_findAddress(ref); tokencount = 1; HT_FREE(ref); } else if (formdata) { /* Keywords are form data */ char * string = argv[arg]; if (tokencount++ <= 1) formfields = HTAssocList_new(); HTParseFormInput(formfields, string); } else { /* keywords are search tokens */ char * escaped = HTEscape(argv[arg], URL_XALPHAS); if (tokencount++ <= 1) keywords = HTChunk_new(128); else HTChunk_putc(keywords, ' '); HTChunk_puts(keywords, HTStrip(escaped)); HT_FREE(escaped); } } } if (!tokencount && !cl->flags & CL_FILTER) { VersionInfo(argv[0]); Cleanup(cl, 0); } /* Should we use persistent cache? */ if (cache) { HTCacheInit(cache_root, 20); /* Should we start by flushing? */ if (flush) HTCache_flushAll(); } /* ** Check whether we should do some kind of cache validation on ** the load */ if (cl->flags & CL_VALIDATE) HTRequest_setReloadMode(cl->request, HT_CACHE_VALIDATE); else if (cl->flags & CL_END_VALIDATE) HTRequest_setReloadMode(cl->request, HT_CACHE_END_VALIDATE); else if (cl->flags & CL_CACHE_FLUSH) HTRequest_setReloadMode(cl->request, HT_CACHE_FLUSH); /* Add progress notification */ if (cl->flags & CL_QUIET) HTAlert_deleteOpcode(HT_A_PROGRESS); /* Output file specified? */ if (cl->outputfile) { if ((cl->output = fopen(cl->outputfile, "wb")) == NULL) { if (SHOW_MSG) HTPrint("Can't open `%s'\\n",cl->outputfile); cl->output = OUTPUT; } } /* ** Set up the output. Even though we don't use this explicit, it is ** required in order to show the stream stack that we know that we are ** getting raw data output on the output stream of the request object. */ HTRequest_setOutputStream(cl->request, HTFWriter_new(cl->request, cl->output, YES)); /* Setting event timeout */ HTHost_setEventTimeout(cl->timer); /* ** Make sure that the first request is flushed immediately and not ** buffered in the output buffer */ HTRequest_setFlush(cl->request, YES); /* Log file specifed? */ if (cl->logfile) { cl->log = HTLog_open(cl->logfile, YES, YES); if (cl->log) HTNet_addAfter(HTLogFilter, NULL, cl->log, HT_ALL, HT_FILTER_LATE); } /* Just convert formats */ if (cl->flags & CL_FILTER) { #ifdef STDIN_FILENO HTRequest_setAnchor(cl->request, (HTAnchor *) cl->anchor); HTRequest_setPreemptive(cl->request, YES); HTLoadSocket(STDIN_FILENO, cl->request); #endif Cleanup(cl, 0); } /* Content Length Counter */ if (cl->flags & CL_COUNT) { HTRequest_setOutputStream(cl->request, HTContentCounter(HTBlackHole(), cl->request, 0x2000)); } /* Rule file specified? */ if (cl->rules) { char * rules = HTParse(cl->rules, cl->cwd, PARSE_ALL); if (!HTLoadRulesAutomatically(rules)) if (SHOW_MSG) HTPrint("Can't access rules\n"); HT_FREE(rules); } /* Add our own filter to update the history list */ HTNet_addAfter(terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST); /* Start the request */ switch (method) { case METHOD_GET: if (formdata) status = HTGetFormAnchor(formfields, (HTAnchor *) cl->anchor, cl->request); else if (keywords) status = HTSearchAnchor(keywords, (HTAnchor *) cl->anchor, cl->request); else status = HTLoadAnchor((HTAnchor *) cl->anchor, cl->request); break; case METHOD_HEAD: if (formdata) { HTRequest_setMethod(cl->request, METHOD_HEAD); status = HTGetFormAnchor(formfields, (HTAnchor *) cl->anchor, cl->request); } else if (keywords) { HTRequest_setMethod(cl->request, METHOD_HEAD); status = HTSearchAnchor(keywords, (HTAnchor *) cl->anchor, cl->request); } else status = HTHeadAnchor((HTAnchor *) cl->anchor, cl->request); break; case METHOD_DELETE: status = HTDeleteAnchor((HTAnchor *) cl->anchor, cl->request); break; case METHOD_POST: if (formdata) { HTParentAnchor * posted = NULL; #if 1 posted = HTPostFormAnchor(formfields, (HTAnchor *) cl->anchor, cl->request); status = posted ? YES : NO; #else /* If we want output to a chunk instead */ post_result = HTPostFormAnchorToChunk(formfields, (HTAnchor *) cl->anchor, cl->request); status = post_result ? YES : NO; #endif } else { if (SHOW_MSG) HTPrint("Nothing to post to this address\n"); status = NO; } break; case METHOD_PUT: status = HTPutDocumentAnchor(cl->anchor, (HTAnchor *) cl->dest, cl->request); break; case METHOD_OPTIONS: status = HTOptionsAnchor((HTAnchor *) cl->anchor, cl->request); break; case METHOD_TRACE: status = HTTraceAnchor((HTAnchor *) cl->anchor, cl->request); break; default: if (SHOW_MSG) HTPrint("Don't know this method\n"); break; } if (keywords) HTChunk_delete(keywords); if (formfields) HTAssocList_delete(formfields); if (status != YES) { if (SHOW_MSG) HTPrint("Sorry, can't access resource\n"); Cleanup(cl, -1); } /* Go into the event loop... */ HTEventList_loop(cl->request); /* Only gets here if event loop fails */ Cleanup(cl, 0); return 0; }
/* Create a Content Type filter stack ** ---------------------------------- ** If a wildcard match is made, a temporary HTPresentation ** structure is made to hold the destination format while the ** new stack is generated. This is just to pass the out format to ** MIME so far. Storing the format of a stream in the stream might ** be a lot neater. ** ** The star/star format is special, in that if you can take ** that you can take anything. */ PUBLIC HTStream * HTStreamStack (HTFormat rep_in, HTFormat rep_out, HTStream * output_stream, HTRequest * request, BOOL guess) { HTList * conversion[2]; int which_list; double best_quality = -1e30; /* Pretty bad! */ HTPresentation *pres, *best_match=NULL; if (rep_out == WWW_RAW) { HTTRACE(CORE_TRACE, "StreamStack. Raw output...\n"); return output_stream ? output_stream : HTErrorStream(); } if (rep_out == rep_in) { HTTRACE(CORE_TRACE, "StreamStack. Identical input/output format (%s)\n" _ HTAtom_name(rep_out)); return output_stream ? output_stream : HTErrorStream(); } #ifdef HTDEBUG if (CORE_TRACE) { const char *p = HTAtom_name(rep_in); const char *q = HTAtom_name(rep_out); HTTRACE(CORE_TRACE, "StreamStack. Constructing stream stack for %s to %s\n" _ p ? p : "<NULL>" _ q ? q : "<NULL>"); } #endif /* HTDEBUG */ conversion[0] = HTRequest_conversion(request); conversion[1] = HTConversions; for(which_list = 0; which_list<2; which_list++) { HTList * cur = conversion[which_list]; while ((pres = (HTPresentation*)HTList_nextObject(cur))) { if ((pres->rep==rep_in || HTMIMEMatch(pres->rep, rep_in)) && (pres->rep_out==rep_out || HTMIMEMatch(pres->rep_out,rep_out))){ if (!best_match || better_match(pres->rep, best_match->rep) || (!better_match(best_match->rep, pres->rep) && pres->quality > best_quality)) { #ifdef HAVE_SYSTEM int result=0; if (pres->test_command) { result = system(pres->test_command); HTTRACE(CORE_TRACE, "StreamStack. system(%s) returns %d\n" _ pres->test_command _ result); } if (!result) { best_match = pres; best_quality = pres->quality; } #else best_match = pres; best_quality = pres->quality; #endif /* HAVE_SYSTEM */ } } } } if (best_match) { if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) { HTTRACE(CORE_TRACE, "StreamStack. Source output\n"); return output_stream ? output_stream : HTErrorStream(); } return (*best_match->converter)(request, best_match->command, rep_in, rep_out, output_stream); } if (rep_out == WWW_SOURCE) { HTTRACE(CORE_TRACE, "StreamStack. Source output\n"); return output_stream ? output_stream : HTErrorStream(); } HTTRACE(CORE_TRACE, "StreamStack. NOT FOUND - error!\n"); return HTBlackHole(); }