/* GNUstepNetscape.c - GSWeb: Netscape NSAPI Interface Copyright (C) 1999 Free Software Foundation, Inc. Written by: Manuel Guesdon Date: Jully 1999 This file is part of the GNUstep Web Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include "GSWUtil.h" #include "GSWDict.h" #include "GSWConfig.h" #include "GSWURLUtil.h" #include "GSWHTTPHeaders.h" #include "GSWAppRequestStruct.h" #include "GSWAppConnect.h" #include "GSWHTTPRequest.h" #include "GSWHTTPResponse.h" #include "GSWAppRequest.h" #define server_portnum port //TODO //#define DEBUG_NETSCAPE // Keywords of obj.conf // Global Doc Root static char* glb_pDocRoot = NULL; #ifdef DEBUG_NETSCAPE static void NSDebugLog(pblock* p_pBlock, const char* p_pszText) { int i; struct pb_entry* entry = NULL; pb_param* nv=NULL; for (i=0;p_pBlock && ihsize;i++) { entry = p_pBlock->ht[i]; while (entry) { nv = entry->param; if (nv) GSWLog(GSW_ERROR,"%s: \t%s = %s",p_pszText,nv->name,nv->value); entry = entry->next; }; }; }; #else #define NSDebugLog(Block,Text) #endif //-------------------------------------------------------------------- // Init NSAPI_PUBLIC int GSWeb_Init(pblock* p_pBlock, Session* p_pSession, Request *p_pRequest) { GSWDict* pDict=NULL; const char* pDocRoot=NULL; int i=0; pDict=GSWDict_New(16); // Get Config Params for (i=0;ihsize;i++) { struct pb_entry* pEntry=p_pBlock->ht[i]; while (pEntry) { pb_param* pParam = pEntry->param; if (pParam) GSWDict_AddStringDup(pDict,pParam->name,pParam->value); pEntry = pEntry->next; }; }; GSWLog_Init(pDict,GSW_INFO); GSWConfig_Init(pDict); // Get The Document Root pDocRoot = GSWDict_ValueForKey(pDict,g_szGSWeb_Conf_DocRoot); if (pDocRoot) { glb_pDocRoot = strdup(pDocRoot); GSWLog(GSW_INFO,NULL,"RootDocument=%s",glb_pDocRoot); } else GSWLog(GSW_INFO,NULL,"no RootDocument"); GSWDict_Free(pDict); GSWLog(GSW_INFO,NULL,"GNUstepWeb initialized"); return REQ_PROCEED; }; //-------------------------------------------------------------------- // NameTrans NSAPI_PUBLIC int GSWeb_NameTrans(pblock *p_pBlock, Session *sn, Request *p_pRequest) { int iRetVal=REQ_PROCEED; GSWURLComponents stURIComponents; const char *pszFrom=NULL; const char *pszURIPath=NULL; const char *pszObjName=NULL; memset(&stURIComponents,0,sizeof(stURIComponents)); pszFrom = pblock_findval(g_szGSWeb_Conf_PathTrans,p_pBlock); pszURIPath = pblock_findval("ppath",p_pRequest->vars); pszObjName = pblock_findval(g_szGSWeb_Conf_Name,p_pBlock); if (!pszFrom || !pszURIPath || !pszObjName) iRetVal=REQ_NOACTION; else if (strncmp(pszFrom,pszURIPath,strlen(pszFrom)) == 0) { // Parse the URL GSWURLError eError=GSWParseURL(&stURIComponents,pszURIPath); if (eError!=GSWURLError_OK) iRetVal=REQ_NOACTION; else { const char *pszAppRoot=NULL; pblock_nvinsert(g_szGSWeb_Conf_Name,(char *)pszObjName,p_pRequest->vars); pszAppRoot = pblock_findval(g_szGSWeb_Conf_AppRoot,p_pBlock); if (pszAppRoot) pblock_nvinsert(g_szGSWeb_Conf_AppRoot,(char *)pszAppRoot,p_pRequest->vars); iRetVal=REQ_PROCEED; }; } else iRetVal=REQ_NOACTION; return iRetVal; }; //-------------------------------------------------------------------- // GNUstepWeb Request Handler NSAPI_PUBLIC int GSWeb_RequestHandler(pblock* p_pBlock, Session* p_pSession, Request* p_pRequest) { int iRetVal=REQ_PROCEED; GSWHTTPResponse* pResponse = NULL; GSWURLError eError=GSWURLError_OK; const char* pszURLError=NULL; char* pszURI=NULL; GSWURLComponents stURLComponents; memset(&stURLComponents,0,sizeof(stURLComponents)); NSDebugLog(p_pSession->client,"Session Client"); NSDebugLog(p_pSession->client,"Session Client"); NSDebugLog(p_pBlock,"pBlock"); NSDebugLog(p_pRequest->vars,"p_pRequest->vars"); NSDebugLog(p_pRequest->reqpb,"p_pRequest->reqpb"); NSDebugLog(p_pRequest->headers,"p_pRequest->headers"); NSDebugLog(p_pRequest->srvhdrs,"p_pRequest->srvhdrs"); // Get the URI pszURI = pblock_findval("uri", p_pRequest->reqpb); // Log it GSWLog(GSW_INFO,NULL,"GNUstepWeb New Request: %s", pszURI); // Parse it // Parse the uri eError=GSWParseURL(&stURLComponents,pszURI); if (eError!=GSWURLError_OK) { pszURLError=GSWURLErrorMessage(eError); // Log the error GSWLog(GSW_INFO,NULL,"URL Parsing Error: %s", pszURLError); if (eError==GSWURLError_InvalidAppName) { pResponse = GSWDumpConfigFile(NULL,&stURLComponents); iRetVal=dieSendResponse(p_pSession,p_pRequest,&pResponse); } else iRetVal=dieWithMessage(p_pSession,p_pRequest,pszURLError); } else { // Build the GSWHTTPRequest with the method GSWHTTPRequest* pRequest= GSWHTTPRequest_New(pblock_findval("method", p_pRequest->reqpb), NULL); // validate the method const char* pszRequestError= GSWHTTPRequest_ValidateMethod(pRequest); if (pszRequestError) { GSWHTTPRequest_Free(pRequest); iRetVal=dieWithMessage(p_pSession,p_pRequest,pszRequestError); } else { // Copy Headers copyHeaders(p_pBlock, p_pSession, p_pRequest, pRequest); // Get Form data // POST Method if ((pRequest->eMethod==ERequestMethod_Post) && (pRequest->uContentLength>0)) { char* pszBuffer = malloc(pRequest->uContentLength); char* pszData = pszBuffer; int c; int i=0; for(i=0;iuContentLength;i++)//TODOV { // Get a character c = netbuf_getc(p_pSession->inbuf); if (c == IO_ERROR) { log_error(0,"GNUstepWeb", p_pSession, p_pRequest, "Error reading form data (Post Method)"); free(pszBuffer); pResponse = GSWHTTPResponse_BuildErrorResponse(NULL,"Bad mojo",NULL); // TODO }; // Add Data *pszData++ = c; } pRequest->pContent = pszBuffer; } // GET Method else if (pRequest->eMethod==ERequestMethod_Get) { // Get the QueryString const char* pQueryString = pblock_findval("query", p_pRequest->reqpb); stURLComponents.stQueryString.pszStart = pQueryString; stURLComponents.stQueryString.iLength = pQueryString ? strlen(pQueryString) : 0; }; // So far, so good... if (!pResponse) { // Now we call the Application ! // get the document root const char* pszDocRoot=getDocumentRoot(p_pRequest); pRequest->pServerHandle = p_pRequest; // Build the response (Beware: tr_handleRequest free pRequest) pResponse=GSWAppRequest_HandleRequest(&pRequest, &stURLComponents, pblock_findval("protocol",p_pRequest->reqpb), pszDocRoot, g_szGSWeb_StatusResponseAppName, //AppTest name NULL); }; // Send the response (if any) if (pResponse) { iRetVal = sendResponse(p_pSession, p_pRequest, pResponse); GSWHTTPResponse_Free(pResponse); } else // No Application Response ! iRetVal = REQ_EXIT; }; }; return iRetVal; }; //-------------------------------------------------------------------- // Get the DocumentRoot static const char *getDocumentRoot(Request* p_pRequest) { const char* pszAppRoot=NULL; // Try to get AppRoot pszAppRoot = pblock_findval(g_szGSWeb_Conf_AppRoot,p_pRequest->vars); if (!pszAppRoot) { // If global AppRoot, take it ! if (glb_pDocRoot) pszAppRoot=glb_pDocRoot; else { httpd_object *dflt=NULL; int iDTable=0; // Get the "default" object dflt = objset_findbyname("default",NULL,p_pRequest->os); // Find the root option for (iDTable=0, pszAppRoot=NULL;dflt && iDTablend && !pszAppRoot;iDTable++) { int j=0; dtable dt=dflt->dt[iDTable]; for (j=0;jheaders->hsize;i++) { struct pb_entry *pEntry=p_pRequest->headers->ht[i]; while (pEntry) { pb_param *header = pEntry->param; if (header) GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,header->name,header->value); pEntry = pEntry->next; }; }; // Add Method if (p_pGSWHTTPRequest->eMethod==ERequestMethod_Post) GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest, g_szServerInfo_RequestMethod, g_szMethod_Post); else GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest, g_szServerInfo_RequestMethod, g_szMethod_Get); // Add server headers copyAHeader("query", p_pRequest->reqpb, p_pGSWHTTPRequest, g_szServerInfo_QueryString); copyAHeader("protocol", p_pRequest->reqpb, p_pGSWHTTPRequest, g_szServerInfo_ServerProtocol); copyAHeader("ip", p_pSession->client, p_pGSWHTTPRequest, g_szServerInfo_RemoteAddress); copyAHeader("auth-user", p_pRequest->vars, p_pGSWHTTPRequest, g_szServerInfo_AuthUser); copyAHeader("auth-type", p_pRequest->vars, p_pGSWHTTPRequest, g_szServerInfo_AuthType); /* AUTH_TYPE pblock_findval("auth-type", p_pRequest->vars); AUTH_USER pblock_findval("auth-user", p_pRequest->vars); uContentLength pblock_findval("content-length", p_pRequest->srvhdrs); CONTENT_TYPE pblock_findval( content-type", p_pRequest->srvhdrs); GATEWAY_INTERFACE "CGI/1.1" HTTP_* pblock_findval( "*", p_pRequest->headers); (* is lower-case, dash replaces underscore) PATH_INFO pblock_findval("path-info", p_pRequest->vars); PATH_TRANSLATED pblock_findval( path-translated", p_pRequest->vars); QUERY_STRING pblock_findval( query", p_pRequest->reqpb); // Only for GET REMOTE_ADDR pblock_findval("ip", p_pSession->client); REMOTE_HOST session_dns(p_pSession) ? session_dns(p_pSession) : pblock_findval("ip", p_pSession->client); REMOTE_IDENT pblock_findval( "from", p_pRequest->headers); REMOTE_USER pblock_findval("auth-user", p_pRequest->vars); REQUEST_METHOD pblock_findval("method", req->reqpb); SCRIPT_NAME pblock_findval("uri", p_pRequest->reqpb); SERVER_NAME char *util_hostname(); SERVER_PORT conf_getglobals()->Vport; (as a string) SERVER_PROTOCOL pblock_findval("protocol", p_pRequest->reqpb); SERVER_SOFTWARE MAGNUS_VERSION_STRING Netscape specific: CLIENT_CERT pblock_findval("auth-cert", p_pRequest->vars); HOST char *session_maxdns(p_pSession); (may be null) HTTPS security_active ? "ON" : "OFF"; HTTPS_KEYSIZE pblock_findval("keysize", p_pSession->client); HTTPS_SECRETKEYSIZE pblock_findval("secret-keysize", p_pSession->client); QUERY pblock_findval( query", p_pRequest->reqpb); // Only for GET SERVER_URL http_uri2url_dynamic("","", p_pSession, p_pRequest); */ // Try to get Host pszHeaderValue = session_maxdns(p_pSession); if (!pszHeaderValue) pszHeaderValue = session_dns(p_pSession); if (pszHeaderValue) GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest, g_szServerInfo_RemoteHost, pszHeaderValue); GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest, g_szServerInfo_ServerSoftware, system_version()); util_itoa(server_portnum, szPort); GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest, g_szServerInfo_ServerPort, szPort); //TODO /* conf_global_vars_s* pServerConf = conf_getglobals(); GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest, "SERVER_NAME",pServerConf->Vserver_hostname); */ pszHeaderValue = getDocumentRoot(p_pRequest); if (pszHeaderValue) GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest, g_szServerInfo_DocumentRoot, pszHeaderValue); }; //-------------------------------------------------------------------- // callback finction to copy an header into p_pRequest static void getHeader(GSWDictElem* p_pElem,Request* p_pRequest) { pblock_nvinsert(p_pElem->pszKey, p_pElem->pValue, ((Request*)p_pRequest)->srvhdrs); }; //-------------------------------------------------------------------- // send response static int sendResponse(Session* p_pSession, Request* p_pRequest, GSWHTTPResponse* p_pResponse) { int iRetVal=REQ_PROCEED; // Process Headers pblock_remove(g_szHeader_ContentType,p_pRequest->srvhdrs); GSWDict_PerformForAllElem(p_pResponse->pHeaders,getHeader,p_pRequest); // Verify content-length if (!pblock_findval(g_szHeader_ContentLength,p_pRequest->srvhdrs)) // !content-length ? { char szLen[64]; util_itoa(p_pResponse->uContentLength,szLen); pblock_nvinsert(g_szHeader_ContentLength,szLen,p_pRequest->srvhdrs); }; // Status protocol_status(p_pSession,p_pRequest,p_pResponse->uStatus,p_pResponse->pszStatusMessage); // HEAD request unattended if (protocol_start_response(p_pSession, p_pRequest) == REQ_NOACTION) { GSWLog(GSW_ERROR,NULL,"protocol_start_response() returned REQ_NOACTION"); iRetVal=REQ_PROCEED; } else if (p_pResponse->uContentLength) { // Send response if (net_write(p_pSession->csd, p_pResponse->pContent, p_pResponse->uContentLength) == IO_ERROR) { GSWLog(GSW_ERROR,NULL,"Failed to send response"); iRetVal=REQ_EXIT; }; }; return iRetVal; }; //-------------------------------------------------------------------- // die/send response static int dieSendResponse(Session* p_pSession, Request* p_pRequest, GSWHTTPResponse** p_ppResponse) { sendResponse(p_pSession, p_pRequest, *p_ppResponse); GSWHTTPResponse_Free(*p_ppResponse); *p_ppResponse=NULL; return REQ_PROCEED; }; //-------------------------------------------------------------------- // die with a message static int dieWithMessage(Session* p_pSession, Request* p_pRequest, const char* p_pszMessage) { GSWHTTPResponse* pResponse=NULL; log_error(0,"GNUstepWeb",NULL,NULL,"Aborting request - %s",p_pszMessage); pResponse = GSWHTTPResponse_BuildErrorResponse(NULL,p_pszMessage,NULL); return dieSendResponse(p_pSession, p_pRequest, &pResponse); };