static void sendFileAsResponse(TSession *const sessionP, TFile *const fileP, const char *const fileName, time_t const fileModTime, MIMEType *const mimeTypeP) { uint64_t const filesize = FileSize(fileP); const char *const mediatype = MIMETypeGuessFromFile2(mimeTypeP, fileName); uint64_t start; /* Defined only if session has one range */ uint64_t end; /* Defined only if session has one range */ switch (sessionP->ranges.size) { case 0: ResponseStatus(sessionP, 200); break; case 1: { bool decoded; decoded = RangeDecode((char *) (sessionP->ranges.item[0]), filesize, &start, &end); if (!decoded) { ListFree(&sessionP->ranges); ResponseStatus(sessionP, 200); } else { const char *contentRange; xmlrpc_asprintf(&contentRange, "bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64, start, end, filesize); ResponseAddField(sessionP, "Content-range", contentRange); xmlrpc_strfree(contentRange); ResponseContentLength(sessionP, end - start + 1); ResponseStatus(sessionP, 206); } } break; default: ResponseContentType(sessionP, "multipart/ranges; boundary=" BOUNDARY); ResponseStatus(sessionP, 206); break; } if (sessionP->ranges.size == 0) { ResponseContentLength(sessionP, filesize); ResponseContentType(sessionP, mediatype); } addLastModifiedHeader(sessionP, fileModTime); ResponseWriteStart(sessionP); if (sessionP->requestInfo.method != m_head) sendBody(sessionP, fileP, filesize, mediatype, start, end); }
/************************************** * SendError * Devuelve el html con el error **************************************/ int XmlRpcServer::SendError(TSession * r, short code,const char *msg) { //POnemos el content type ResponseContentType(r, (char*)"text/html; charset=\"utf-8\""); //Escribimos el codigo de error return SendResponse(r,code,(char*)msg,strlen(msg)); }
static void handleDirectory(TSession *const sessionP, const char *const dirName, time_t const fileModTime, MIMEType *const mimeTypeP) { bool text; bool ascending; uint16_t sort; /* 1=by name, 2=by date */ const char *error; determineSortType(sessionP->requestInfo.query, &ascending, &sort, &text, &error); if (error) { ResponseStatus(sessionP, 400); xmlrpc_strfree(error); } else if (notRecentlyModified(sessionP, fileModTime)) { ResponseStatus(sessionP, 304); ResponseWriteStart(sessionP); } else { TPool pool; bool succeeded; succeeded = PoolCreate(&pool, 1024); if (!succeeded) ResponseStatus(sessionP, 500); else { TList list; uint16_t responseStatus; const char *error; generateListing(&list, dirName, sessionP->requestInfo.uri, &pool, &error, &responseStatus); if (error) { ResponseStatus(sessionP, responseStatus); xmlrpc_strfree(error); } else { ResponseStatus(sessionP, 200); ResponseContentType(sessionP, text ? "text/plain" : "text/html"); addLastModifiedHeader(sessionP, fileModTime); ResponseChunked(sessionP); ResponseWriteStart(sessionP); if (sessionP->requestInfo.method != m_head) sendDirectoryDocument(&list, ascending, sort, text, sessionP->requestInfo.uri, mimeTypeP, sessionP); HTTPWriteEndChunk(sessionP); ListFree(&list); } PoolFree(&pool); } } }
static void sendResponse(xmlrpc_env * const envP, TSession * const abyssSessionP, const char * const body, size_t const len, bool const chunked, ResponseAccessCtl const accessControl) { /*---------------------------------------------------------------------------- Generate an HTTP response containing body 'body' of length 'len' characters. This is meant to run in the context of an Abyss URI handler for Abyss session 'abyssSessionP'. -----------------------------------------------------------------------------*/ const char * http_cookie = NULL; /* This used to set http_cookie to getenv("HTTP_COOKIE"), but that doesn't make any sense -- environment variables are not appropriate for this. So for now, cookie code is disabled. - Bryan 2004.10.03. */ /* Various bugs before Xmlrpc-c 1.05 caused the response to be not chunked in the most basic case, but chunked if the client explicitly requested keepalive. I think it's better not to chunk, because it's simpler, so I removed this in 1.05. I don't know what the purpose of chunking would be, and an original comment suggests the author wasn't sure chunking was a good idea. In 1.06 we added the user option to chunk. */ if (chunked) ResponseChunked(abyssSessionP); ResponseStatus(abyssSessionP, 200); if (http_cookie) /* There's an auth cookie, so pass it back in the response. */ addAuthCookie(envP, abyssSessionP, http_cookie); if ((size_t)(uint32_t)len != len) xmlrpc_faultf(envP, "XML-RPC method generated a response too " "large for Abyss to send"); else { uint32_t const abyssLen = (uint32_t)len; /* See discussion below of quotes around "utf-8" */ ResponseContentType(abyssSessionP, "text/xml; charset=utf-8"); ResponseContentLength(abyssSessionP, abyssLen); ResponseAccessControl(abyssSessionP, accessControl); ResponseWriteStart(abyssSessionP); ResponseWriteBody(abyssSessionP, body, abyssLen); ResponseWriteEnd(abyssSessionP); } }
void Answer(TSession *r, uint16_t statuscode, char *buffer) { ResponseChunked(r); ResponseStatus(r,statuscode); ResponseContentType(r,"text/html"); ResponseWriteStart(r); HTTPWrite(r,"<HTML><BODY>",12); HTTPWrite(r,buffer,strlen(buffer)); HTTPWrite(r,"</BODY></HTML>",14); HTTPWriteEnd(r); }
static abyss_bool ServerFileHandler(TSession * const r, char * const z, time_t const fileModTime, MIMEType * const mimeTypeP) { const char * mediatype; TFile file; uint64_t filesize; uint64_t start; uint64_t end; TDate date; char * p; TDate filedate; mediatype = MIMETypeGuessFromFile2(mimeTypeP, z); if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) { ResponseStatusErrno(r); return TRUE; } fileDate(r, fileModTime, &filedate); p = RequestHeaderValue(r, "if-modified-since"); if (p) { if (DateDecode(p,&date)) { if (DateCompare(&filedate, &date) <= 0) { ResponseStatus(r, 304); ResponseWrite(r); return TRUE; } else r->ranges.size = 0; } } filesize = FileSize(&file); switch (r->ranges.size) { case 0: ResponseStatus(r, 200); break; case 1: { abyss_bool decoded; decoded = RangeDecode((char *)(r->ranges.item[0]), filesize, &start, &end); if (!decoded) { ListFree(&(r->ranges)); ResponseStatus(r, 200); break; } sprintf(z, "bytes %llu-%llu/%llu", start, end, filesize); ResponseAddField(r, "Content-range", z); ResponseContentLength(r, end - start + 1); ResponseStatus(r, 206); } break; default: ResponseContentType(r, "multipart/ranges; boundary=" BOUNDARY); ResponseStatus(r, 206); break; } if (r->ranges.size == 0) { ResponseContentLength(r, filesize); ResponseContentType(r, mediatype); } if (DateToString(&filedate, z)) ResponseAddField(r, "Last-Modified", z); ResponseWrite(r); if (r->request_info.method != m_head) sendBody(r, &file, filesize, mediatype, start, end, z); FileClose(&file); return TRUE; }
static abyss_bool ServerDirectoryHandler(TSession * const r, char * const z, time_t const fileModTime, MIMEType * const mimeTypeP) { TList list; abyss_bool text; abyss_bool ascending; uint16_t sort; /* 1=by name, 2=by date */ TPool pool; TDate date; const char * error; uint16_t responseStatus; TDate dirdate; const char * imsHdr; determineSortType(r->request_info.query, &ascending, &sort, &text, &error); if (error) { ResponseStatus(r,400); xmlrpc_strfree(error); return TRUE; } fileDate(r, fileModTime, &dirdate); imsHdr = RequestHeaderValue(r, "If-Modified-Since"); if (imsHdr) { if (DateDecode(imsHdr, &date)) { if (DateCompare(&dirdate, &date) <= 0) { ResponseStatus(r, 304); ResponseWrite(r); return TRUE; } } } if (!PoolCreate(&pool, 1024)) { ResponseStatus(r, 500); return TRUE; } generateListing(&list, z, r->request_info.uri, &pool, &error, &responseStatus); if (error) { ResponseStatus(r, responseStatus); xmlrpc_strfree(error); PoolFree(&pool); return TRUE; } /* Send something to the user to show that we are still alive */ ResponseStatus(r, 200); ResponseContentType(r, (text ? "text/plain" : "text/html")); if (DateToString(&dirdate, z)) ResponseAddField(r, "Last-Modified", z); ResponseChunked(r); ResponseWrite(r); if (r->request_info.method!=m_head) sendDirectoryDocument(&list, ascending, sort, text, r->request_info.uri, mimeTypeP, r, z); HTTPWriteEndChunk(r); /* Free memory and exit */ ListFree(&list); PoolFree(&pool); return TRUE; }
/************************************** * ProcessRequest * Procesa una peticion *************************************/ int XmlHandler::ProcessRequest(TRequestInfo *req,TSession * const ses) { xmlrpc_env env; int inputLen; char *method; xmlrpc_value *params = NULL; timeval tv; Log(">ProcessRequest [uri:%s]\n",req->uri); //Init timer getUpdDifTime(&tv); //Creamos un enviroment xmlrpc_env_init(&env); //Si no es post if (req->method != m_post) //Mandamos error return XmlRpcServer::SendError(ses, 405, "Only POST allowed"); //Obtenemos el content type const char * content_type = RequestHeaderValue(ses, (char*)"content-type"); //Si no es el bueno if (content_type == NULL || strcmp(content_type, "text/xml") != 0) return XmlRpcServer::SendError(ses, 400, "Wrong content-type"); //Obtenemos el content length const char * content_length = RequestHeaderValue(ses, (char*)"content-length"); //Si no hay if (content_length == NULL) return XmlRpcServer::SendError(ses,411,"No content-length"); //Obtenemos el entero inputLen = atoi(content_length); //Tiene que ser mayor que cero if ((inputLen < 0) || (inputLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))) return XmlRpcServer::SendError(ses,400,"Size limit"); //Creamos un buffer para el body char * buffer = (char *) malloc(inputLen); if (!XmlRpcServer::GetBody(ses,buffer,inputLen)) { //LIberamos el buffer free(buffer); //Y salimos sin devolver nada Log("Operation timedout\n"); return 1; } //Get method name xmlrpc_parse_call(&env,buffer,inputLen,(const char**)&method,¶ms); Log("-ProcessRequest [method:%s]\n",method); //Free name and params free(method); xmlrpc_DECREF(params); //Generamos la respuesta xmlrpc_mem_block *output = xmlrpc_registry_process_call( &env, registry, NULL, buffer, inputLen ); //Si todo ha ido bien if (!env.fault_occurred) { //POnemos el content type ResponseContentType(ses, (char*)"text/xml; charset=\"utf-8\""); //Y mandamos la respuesta XmlRpcServer::SendResponse(ses,200,XMLRPC_MEMBLOCK_CONTENTS(char, output), XMLRPC_MEMBLOCK_SIZE(char, output)); } else
void AbyssServer::Session::setRespContentType(string const& contentType) { ResponseContentType(this->implP->cSessionP, contentType.c_str()); }