RE: HTTP Authentication with libwww + POST + XML + arguments + headers

 
> As I see from the mailing list postings, this issue is covered
frequently.
> I'm still having trouble!  I got a great deal of help from Josh Watts'
> posting back in 2001, but my application still isn't working.

I believe I sent some code on this, not long ago. I have been using the
code that follows as a generic http request library. The only things I
haven't implemented that I might are saving the ftp results (I only
check if it the file is there) and ssl. Look for 'basic' authentication
below and you'll be ok. All you need to use the library is define your
own debug function.

Changed the subject to add some keywords.

/* wwwapi.h */

#ifdef __cplusplus
extern "C" {
#endif

extern void www_init (void);
extern void www_terminate (void);
extern int www_request (char* outputformat, char **HTMLheader, char **
HTMLresponse, char *url, char *username, char *password, ...);

#ifdef __cplusplus
}
#endif


#include "wwwapi.h"
#include "WWWHTTP.h"
#include "WWWInit.h"
#include "HTUTree.h"
#include "HTNet.h"
#include "HTAABrow.h"


/*
** Local context structure used in the HTNet object.
*/
typedef enum _HTFTPState {
    FTP_SUCCESS	= -2,
    FTP_ERROR = -1,
    FTP_BEGIN = 0,
    FTP_NEED_CCON,				       /* Control
connection */
    FTP_NEED_LOGIN,
    FTP_NEED_DCON,					  /* Data
connection */
    FTP_NEED_DATA,
    FTP_NEED_SERVER				   /* For directory
listings */
} HTFTPState;

typedef struct _ftp_ctrl {
    HTChunk *		cmd;
    int			repcode;
    char *		reply;
    char *		uid;
    char *		passwd;
    char *		account;
    HTFTPState     	state;			  /* State of the
connection */
    int 		substate;		  /* For hierarchical
states */
    BOOL		sent;			    /* Read or write
command */
    BOOL		cwd;					 /* Done
cwd */
    BOOL		reset;			 	  /* Expect
greeting */
    FTPServerType	server;		         	   /* Type of
server */
    HTNet *		cnet;			       /* Control
connection */
    HTNet *		dnet;			   	  /* Data
connection */
    BOOL		alreadyLoggedIn;
} ftp_ctrl;

// variable length string that gets the entire response
HTChunk * result_chunk = NULL;


// Avoid printing progress messages
PUBLIC BOOL HTProgress (HTRequest * request, HTAlertOpcode op,
			int msgnum, const char * dfault, void * input,
			HTAlertPar * reply)
{
    char * msg = HTDialog_progressMessage(request, op, msgnum, dfault,
input);
    if (msg) {
	debug(D_DEBUG,"%s\n", msg);
	HT_FREE(msg);
    }
    if (reply) return YES;
    return YES;
}


// Declaration and constructor for authentication information.
typedef struct _MYBasic {		  /* Basic challenge and
credentials */
  char *	uid;
  char *	pw;
  BOOL	retry;			    /* Should we ask the user again? */
  BOOL	proxy;			    /* Proxy authentication */
} MYBasic;

PRIVATE MYBasic * MYBasic_new(char * username, char* password)
{
  MYBasic * me = NULL;
  if ((me = (MYBasic *) HT_CALLOC(1, sizeof(MYBasic))) == NULL)
    HT_OUTOFMEM("MYBasic_new");
  me->uid = strdup(username); 
  me->pw = strdup(password); 
  me->retry = NO; 
  me->proxy = NO; 
  return me;
}

PRIVATE int printer (const char * fmt, va_list pArgs)
{
  s_debug(D_DEBUG, fmt, pArgs);
  return 0;
}

PRIVATE int tracer (const char * fmt, va_list pArgs)
{
  s_debug(D_ANALYSIS, fmt, pArgs);
  return 0;
}

PRIVATE int terminate_handler (HTRequest * request, HTResponse *
response,
			       void * param, int status) 
{
  char statuscode[64];
  sprintf (statuscode,"%d",status);
  HTResponse_addHeader(response,"status",statuscode);
  HTEventList_stopLoop ();
  if (request && response && param) return status;
  return status;
}

void www_init(void) {
  /* Need our own trace and print functions */
  HTPrint_setCallback(printer);
  HTTrace_setCallback(tracer);

  /* Get trace messages */
  if (log_facilities & D_ANALYSIS) {
    HTSetTraceMessageMask("sop");
  }

  /* Add our own filter to update the history list */
  HTNet_addAfter(terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST);

  /* Set the timeout for long we are going to wait for a response */
  HTHost_setEventTimeout(20000);

  /* Initialize libwww core */
  HTProfile_newNoCacheClient("TestApp", "1.0");

  HTAlert_setInteractive(NO);
}

void www_terminate(void) {
  /* Terminate the Library */
  HTProfile_delete();
}

int www_request (char* outputformat, char **HTMLheader, char **
HTMLresponse, char *url, char *username, char *password, ...) {
  // Everything requires a request stream
  HTRequest * request = HTRequest_new();
  // Anchor holding the URL. Need it for POST requests
  HTAnchor * anchor = NULL;
  // Structure holding authentication info
  MYBasic * basic;
  /* ftp Automatic Authentication */
  HTNet * cnet; 
  ftp_ctrl * ctrl; 

  char * cwd = HTGetCurrentDirectoryURL();
  char * absolute_url;
  char * name_value=NULL;
  int RETURNVALUE=0;

  // Get arbitrary number of arguments for the cgi we will call
  // Put the arguments in an association list, to be used in PUT and GET
requests
  HTAssocList * formfields = NULL;

  va_list argsvar;
  va_start (argsvar, password);
  name_value=va_arg(argsvar,char *);
  if (name_value) {
    formfields = HTAssocList_new ();
    do {
      HTParseFormInput(formfields,name_value);
      debug(D_DEBUG,"argument '%s'", name_value);
      name_value=va_arg(argsvar,char *);
    } while (name_value);
  }
  va_end(argsvar);

  if (!url) return 1;

  debug(D_DEBUG,"www_request %s", url);

  // Escape illegal characters. Basically spaces and greek letters
  absolute_url = HTParse(url, cwd, PARSE_ALL);

  /* We want raw output including headers */
  if (strcmp(outputformat,"xml") == 0) {
    HTRequest_setOutputFormat(request, HTAtom_for("text/xml"));
  } else {
    HTRequest_setOutputFormat(request, WWW_SOURCE);
  }
  /* Close connection immediately */
  HTRequest_addConnection(request, "close", "");

  /* Automatic Authentication */
  if (username && password) {
    basic = MYBasic_new(username,password);
    HTBasic_generate (request, basic, 0);
  }

  debug(D_DEBUG,"absolute_url=%s",absolute_url);
  /* Get an anchor object for the URL */
  anchor = HTAnchor_findAddress(absolute_url);

  // Load the url
  if (formfields) {
    // Load with a POST
    result_chunk = HTPostFormAnchorToChunk(formfields, anchor, request);
  
    /* Clean up the form fields */
    HTAssocList_delete(formfields);

  } else {
    // Load with a GET
    result_chunk = HTLoadAnchorToChunk (anchor, request);
  }

  HT_FREE(absolute_url);
  HT_FREE(cwd);
  (*HTMLheader) = NULL;
  (*HTMLresponse) = NULL;

  // Set the username and password for ftp requests
  if (strcmp("ftp",outputformat) == 0) {
    cnet = HTRequest_net(request);
    ctrl = (ftp_ctrl *) HTNet_context(cnet);
    if (ctrl) {
      StrAllocCopy(ctrl->uid, username);
      StrAllocCopy(ctrl->passwd, password);
    }
  }

  if (result_chunk) {
    /* Go into the event loop... */
    HTEventList_loop(request);
    (*HTMLresponse) = HTChunk_toCString(result_chunk);
    debug(D_ANALYSIS, "Response : %s", *HTMLresponse);
    // Get headers and status code
    {
      HTResponse *response = HTRequest_response(request);
      if (response) {
	HTAssocList * headers = HTResponse_header(response);
	if (headers) {
	  HTAssoc * pres;
	  (*HTMLheader) = (char *) malloc (sizeof(char) * 1024);
	  (*HTMLheader)[0] = '\0';
	  while ((pres = (HTAssoc *) HTAssocList_nextObject(headers))) {
	    char * name = HTAssoc_name(pres);
	    char * value = HTAssoc_value(pres);
	    if (strcmp(name,"status") == 0) {
	      RETURNVALUE = atoi(value);
	    } else {
	      debug(D_DEBUG,"HEADER %s = %s", name, value);
	      sprintf(*HTMLheader,"%s%s = %s\n",*HTMLheader,name,value);
	    }
	  }
	}
      }
    }

  }

  /* Clean up the request */
  HTRequest_delete(request);
  return RETURNVALUE;
}

Received on Friday, 19 September 2003 00:35:27 UTC