/* ** Libwww extension test file ** ** This program shows how to use the extension methods available in Libwww. ** Through these methods (METHOD_EXT_0 to METHOD_EXT_6), applications may ** register (by calling HTMethod_setExtensionMethod) new methods, that may be ** unknown for the Libwww, and use them for its request. See HTMethod.html for ** details. ** ** More libwww samples can be found at "http://www.w3.org/Library/Examples/" ** ** Copyright © 1995-1998 World Wide Web Consortium, (Massachusetts ** Institute of Technology, Institut National de Recherche en ** Informatique et en Automatique, Keio University). All Rights ** Reserved. This program is distributed under the W3C's Software ** Intellectual Property License. This program is distributed in the hope ** that it will be useful, but WITHOUT ANY WARRANTY; without even the ** implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ** PURPOSE. See W3C License http://www.w3.org/Consortium/Legal/ for more ** details. ** ** ** Authors: ** MKP Manuele Kirsch Pinheiro (Manuele.Kirsch_Pinheiro@inrialpes.fr, manuele@inf.ufrgs.br) ** _ Project CEMT (INRIA Rhone-Alpes,France / UFRGS-II,Brazil) _ ** ** History: ** fev, 2002 created MKP ** may, 2002 modifications for MKP ** windows plataform. ** ** $Id: myext.c,v 1.2 2002/05/30 18:08:56 kirschpi Exp $ */ #include "WWWLib.h" #include "WWWInit.h" #include "WWWApp.h" #include "WWWXML.h" #include "WWWHTTP.h" #ifndef W3C_VERSION #define W3C_VERSION "Unspecified" #endif #define APP_NAME "MyExt" #define APP_VERSION "3.0" #if defined(__svr4__) #define CATCH_SIG #endif /* ** error codes for use in error_callback filter */ #define ERR_UNKNOWN 0x0 #define ERR_FATAL 0x1 #define ERR_NON_FATAL 0x2 #define ERR_WARN 0x4 #define ERR_INFO 0x8 /* ** Some compilers, like MSVC, doesn't know STDIN_FILENO */ #ifndef STDIN_FILENO #define STDIN_FILENO fileno(stdin) #endif /* ** Request context */ typedef struct _Context { HTChunk * chunk; int depth; } Context; /* ** Application context */ typedef struct _App { HTRequest * console_request; HTEvent * console_event; HTList * active; /* List of active contexts */ HTMethod method; } App; /* ** Callback functions */ PRIVATE HTEventCallback console_parser; PRIVATE HTNetAfter request_terminater; PRIVATE HTNetAfter local_request_terminater; PRIVATE HTNetAfter local_request_first; PRIVATE HTNetAfter error_callback; PRIVATE int printer (const char * fmt, va_list pArgs); PRIVATE int tracer (const char * fmt, va_list pArgs); /* ** Prototypes */ PRIVATE App * App_new (void); PRIVATE BOOL App_delete (App * me); PRIVATE void Context_new (HTRequest * request, HTChunk * chunk, App * app); PRIVATE void Context_delete (Context * ctx); PRIVATE HTRequest * Request_new (App * app); PRIVATE BOOL Request_delete (App * app, HTRequest * request); PRIVATE int request_terminater (HTRequest * request, HTResponse * response, void * param, int status); PRIVATE int console_parser (SOCKET s, void * param, HTEventType type); PRIVATE int local_request_terminater (HTRequest * request, HTResponse * response, void * param, int status); PRIVATE int local_request_first (HTRequest * request, HTResponse * response, void * param, int status); PRIVATE int error_callback (HTRequest * request, HTResponse * response, void * param, int status); PRIVATE App * Init (void); PRIVATE void my_headers (HTRequest *request); PRIVATE void my_get_document (App *app, char *dst); PRIVATE char * create_body (void); /* --------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------- */ /* EXPAT HANDLERS */ /* ------------------------------------------------------------------------- */ PRIVATE void XML_startElement (void * userData, const XML_Char *name, const XML_Char ** atts) { int *depth = (int *)userData; int i=0; if (name) { for (i=0;i<(*depth);i++) HTPrint (" "); HTPrint("%s: ", name); for (i = 0; atts[i]; i += 2) HTPrint(" %s='%s'", atts[i], atts[i + 1]); HTPrint ("\n"); } *depth += 1; } PRIVATE void XML_endElement (void * userData, const XML_Char * name) { int *depth = (int *)userData; *depth -= 1; } PRIVATE void XML_characterData (void * userData, const XML_Char * s, int len) { int *depth = (int *) userData; int i=0; if (len>1) { for (i=-1;i<(*depth);i++) HTPrint (" "); for (i=0;idepth) ); } } PRIVATE void HTXML_newInstance (HTStream * me, HTRequest * request, HTFormat target_format, HTStream * target_stream, XML_Parser xmlparser, void * context) { HTPrint ("MyExt: HTXML_newInstance\n"); if (me && xmlparser) HTXML_setHandlers(xmlparser,request); } /* ------------------------------------------------------------------------- */ /* ** CRCLCleanUp: removes CR, LF and CRLF characters from the string */ PUBLIC void CRLFCleanUp (char *buf,int size) { int i; if(buf && *buf) { for (i=0;iconsole_request = HTRequest_new(); me->console_event = HTEvent_new(console_parser, me, HT_PRIORITY_MAX, -1); me->active = HTList_new(); /* Register stdin as our console */ if (isatty(STDIN_FILENO)) HTEventList_register(STDIN_FILENO, HTEvent_READ, me->console_event); /* Add our own request terminate handler */ HTNet_addAfter(request_terminater, NULL, me, HT_ALL, HT_FILTER_LAST); HTPrint ("MyExt: Application context created\n"); /* Set Extension method 0 to PROPFIND */ HTPrint ("MyExt: Setting method %x to PROPFIND\n",METHOD_EXT_0); if (HTMethod_setExtensionMethod (METHOD_EXT_0, "PROPFIND",NO)) me->method = METHOD_EXT_0; else { HTPrint ("MyExt: Extension method FAILED - using GET\n"); me->method = METHOD_GET; } HTPrint ("ENTER A URL: \n"); return me; } /* ** App_delete : removes an application context object ** Parameter : App * app application context to be removed ** Returns : BOOL YES - operation succed ** NO - operation failed */ PRIVATE BOOL App_delete (App * me) { HTRequest * req = NULL; HTPrint ("MyExt: Removing application context\n"); if (me) { /* killing any remaining active requests */ HTNet_killAll(); /* freeing all remaining request objects */ while (!HTList_isEmpty(me->active)) { req = (HTRequest *) HTList_nextObject (me->active); if (req) Request_delete (me,req); } /* clean up everything */ HTRequest_delete(me->console_request); HTEvent_delete (me->console_event); HTList_free (me->active); /* clean up extension method */ HTPrint ("Removing extension method\n"); if (HTMethod_deleteExtensionMethod (METHOD_EXT_0)) HTPrint ("MyExt: Extension method deleted \n"); HT_FREE(me); /* stopping event loop */ HTEventList_stopLoop(); /* Terminate libwww */ HTProfile_delete(); return YES; } return NO; } /* ** Context_new : creates a new request context ** Parameters : HTRequest * request ** HTChunk * chunk ** App * app */ PRIVATE void Context_new (HTRequest * request, HTChunk * chunk, App * app) { Context * ctx = NULL; if ( (ctx = (Context *) HT_CALLOC(1, sizeof(Context))) == NULL ) { App_delete (app); HT_OUTOFMEM("Contect_new"); } HTPrint ("MyExt: Setting request context...\n"); ctx->depth = 0; ctx->chunk = chunk; HTRequest_setContext(request,ctx); } /* ** Context_delete : removes the request context ** Parameters : Context * ctx */ PRIVATE void Context_delete (Context * ctx) { if (ctx && ctx->chunk) { HTPrint ("MyExt: Removing request context...\n"); HTChunk_delete (ctx->chunk); HT_FREE (ctx); } } /* ** Request_new : creates a new request ** Parameters : App * app application context ** Returns : HTRequest * */ PRIVATE HTRequest * Request_new (App * app) { HTRequest * request = HTRequest_new(); HTPrint ("MyExt: creating a new request\n"); /* setting request format */ HTRequest_setOutputFormat(request, HTAtom_for ("text/xml")); HTRequest_setOutputFormat(request, WWW_SOURCE); HTRequest_addConnection (request,"close",""); /* method */ HTPrint ("MyExt: Setting method in the request\n"); if (app) HTRequest_setMethod (request,app->method); else { HTPrint ("MyExt: No App, using default method\n"); HTRequest_setMethod (request,METHOD_GET); } /* some headers */ HTRequest_addExtraHeader (request,"Depth","0"); HTRequest_addCacheControl (request, "no-cache",""); /* proxy - no cache */ HTRequest_addGnHd (request,HT_G_PRAGMA_NO_CACHE); /* set some local filters */ HTRequest_addAfter (request, local_request_terminater, NULL, app, \ HT_ALL ,HT_FILTER_LAST , NO); HTRequest_addAfter (request, local_request_first, NULL, app, \ HT_ALL ,HT_FILTER_FIRST , NO); HTRequest_addAfter (request,error_callback, NULL, app, \ HT_ERROR, HT_FILTER_LAST, NO); if (!app->active) app->active = HTList_new(); HTList_addObject(app->active, request); HTRequest_setFlush(request, YES); /* register XML callback */ HTXMLCallback_registerNew (HTXML_newInstance, NULL); return request; } /* ** Request_delete : removes a request ** Parameters : App * app application context ** HTRequest * request ** Returns : BOOL YES if operation succeed ** NO if operation failed */ PRIVATE BOOL Request_delete (App * app, HTRequest * request) { HTPrint ("MyExt: removing request\n"); if (app && app->active && request) { HTPrint ("MyExt: Request deleted \n"); HTList_removeObject(app->active, request); HTRequest_delete(request); return YES; } return NO; } /* ** console_parser : treats the user's interaction on the console ** Function's type : HTEventCallback */ PRIVATE int console_parser (SOCKET s, void * param, HTEventType type) { App * app = (App *) param; char buf[128]; char * full_dst; char * cwd; /* reading console */ if (!fgets(buf, sizeof(buf), stdin)) return HT_ERROR; if (toupper(buf[0]) == 'Q') { /* Quit the program */ App_delete(app); exit (0); } else { /* take the target address */ CRLFCleanUp (buf,strlen(buf)); HTPrint ("MyExt: Console readed **%s**\n",buf); cwd = HTGetCurrentDirectoryURL(); full_dst = HTParse (buf,cwd,PARSE_ALL); HTPrint ("Getting %s\n",full_dst); /* load the document */ my_get_document (app,full_dst); HT_FREE (full_dst); HT_FREE (cwd); } return HT_OK; } /* ** request_terminater : global filter to delete the requests ** Funtion's type : HTNetAfter */ PRIVATE int request_terminater (HTRequest * request, HTResponse * response, void * param, int status) { App * app = (App *) param; Context * ctx = NULL; HTPrint ("MyExt: GLOBAL FILTER (request_terminater)\n"); ctx = (Context *) HTRequest_context(request); HTPrint ("MyExt: context object deleted\n"); Context_delete (ctx); Request_delete(app, request); HTPrint ("Ready! Enter a New URL: "); return HT_OK; } /* ** local_request_terminater : local after filter to treat the request's results ** Function's type : HTNetAfter */ PRIVATE int local_request_terminater (HTRequest * request, HTResponse * response, void * param, int status) { Context * ctx = NULL; HTPrint ("\tstatus: %d\n",status); if (response) { HTPrint ("\tContent-length: %d \n\tIs Cachable: %c\n\tis Cached: %c \n\tReason: %s\n", \ HTResponse_length(response),\ (HTResponse_isCachable(response))?'Y':'N', (HTResponse_isCached(response,YES))?'Y':'N', (HTResponse_reason(response))?HTResponse_reason(response):"NULL"); HTPrint ("\tFormat : %s \n",(char *)HTAtom_name(HTResponse_format(response))); } else HTPrint ("\tResponse NULL\n"); ctx = (Context *) HTRequest_context(request); if ( ctx && ctx->chunk && HTChunk_data(ctx->chunk)) HTPrint ("MyExt: Loaded: \n%s\n",HTChunk_data(ctx->chunk)); else HTPrint ("MyExt: No text/xml data available at Chunk\n"); return HT_OK; } /* ** local_request_first : local after filter to treat the request's headers ** Function's type : HTNetAfter */ PRIVATE int local_request_first (HTRequest * request, HTResponse * response, void * param, int status) { my_headers (request); return HT_OK; } /* ** error_callback : global after filter to treat the request's errors ** Function's type : HTNetAfter */ PRIVATE int error_callback (HTRequest * request, HTResponse * response, void * param, int status) { App * app = (App *) param; HTList * error_list = NULL; HTError * error = NULL; HTPrint ("MyExt: ERROR CALLBACK\n"); HTPrint ("\tapp %s \n\trequest %s \n\tresponse %s \n\tstatus %d\n", \ (app)?"OK":"NULL",(request)?"OK":"NULL",\ (response)?"OK":"NULL",status); if (request) { error_list = HTRequest_error (request); while (error_list && (error = (HTError *) HTList_nextObject(error_list))) { HTPrint ("\tError location %s\n",HTError_location(error)); switch (HTError_severity(error)) { case ERR_UNKNOWN : HTPrint ("\tSeverity : UNKNOWN\n"); break; case ERR_FATAL : HTPrint ("\tSeverity : FATAL\n"); break; case ERR_NON_FATAL : HTPrint ("\tSeverity : NON FATAL\n"); break; case ERR_WARN : HTPrint ("\tSeverity : WARN\n"); break; case ERR_INFO : HTPrint ("\tSeverity : INFO\n"); break; default : HTPrint ("\tSeverity : %Xd\n",HTError_severity(error)); break; } } } return HT_OK; } /* ** Init : application initialization ** Returns : App * application context */ PRIVATE App * Init (void) { App * app = NULL; HTPrint ("MyExt: starting application\n"); /* Initiate libwww */ HTProfile_newHTMLNoCacheClient(APP_NAME, APP_VERSION); HTTP_setConnectionMode(HTTP_11_NO_PIPELINING); app = App_new(); /* Gotta set up our own traces */ HTPrint_setCallback(printer); HTTrace_setCallback(tracer); #if 0 HTSetTraceMessageMask("sapol"); #endif HTEventList_newLoop(); return app; } /* ** my_headers : shows anchor's headers ** Parameters : HTRequest * request */ PRIVATE void my_headers (HTRequest *request) { HTAssoc * h = NULL; HTAssocList * headers = NULL; HTParentAnchor * anchor = NULL; HTPrint ("MyExt: Searching headers...\n"); anchor = HTRequest_anchor (request); headers = HTAnchor_header(anchor); h = HTAssocList_nextObject(headers); while (anchor && headers && h ) { HTPrint ("\t%s : %s\n",HTAssoc_name(h),HTAssoc_value(h)); h = HTAssocList_nextObject(headers); } } /* ** my_get_document: retrives the document ** Parameters: App * app application context ** char * dst URL destiny */ PRIVATE void my_get_document (App *app, char *dst) { char * body = create_body(); HTRequest * request = NULL; HTChunk * chunk = NULL; HTPrint ("MyExt: loading document\n"); request = Request_new (app); /* set body */ HTRequest_setMessageBody(request,body); HTRequest_setMessageBodyFormat (request,HTAtom_for("text/xml")); HTRequest_setMessageBodyLength (request,strlen(body)); if ( request && (chunk = HTLoadToChunk (dst,request))) { HTPrint ("MyExt: setting context\n"); Context_new (request,chunk,app); } else HTPrint ("MyExt: load to chunk failed\n"); HT_FREE (body); } PRIVATE char * create_body (void) { char tmp[4096]; char * body = NULL; char nl[3]; sprintf (nl,"%c%c",CR,LF); sprintf (tmp,""); strcat (tmp,nl); strcat (tmp,""); strcat (tmp,nl); strcat (tmp," "); strcat (tmp,nl); strcat (tmp,""); if ( (body = HT_MALLOC (strlen(tmp)+4)) != NULL) sprintf (body,"%s%c",tmp,'\0'); return body; } /* ******************************************************************** */ int main (int argc, char ** argv) { App * app = NULL; app = Init(); return 0; }