int handle_http_post(http_req * req, http_rsp * rsp) { HashElement * e = NULL; int httpbodylen = 0; int readlen = 0; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif e = HashLookup(req->headOptions, "Content-Length"); if(!e) { /* RFC2616, 14.23. */ WEBLOG_ERROR("<%s> Missing \"Content-Length\" in POST/PUT.\n", __FUNCTION__); return handle_http_error(400, req, rsp); } httpbodylen = atoi(e->value.data.string); WEBLOG_INFO("<%s> Content-Length:%d.\n", __FUNCTION__, httpbodylen); /* Even if we don't care about the data, we should either : 1. close the socket. 2. read all data out of the socket. This is to enure a keep-alive socket won't fail in next loop. */ if(req->datalen > 0) // data left in head buffer. readlen += req->datalen; /* if there's more data in socket.... */ while(readlen < httpbodylen) { req->datalen = recv(req->sock, req->sockbuf, sizeof(req->sockbuf), 0); if(req->datalen < 0) { print_socket_error(); break; } else if(req->datalen == 0) { WEBLOG_INFO("<%s> client closed. data progress: %d/%d.\n", __FUNCTION__, readlen, httpbodylen); break; } readlen += req->datalen; WEBLOG_VERBOSE("<%s> progress: %10d/%d. \n", __FUNCTION__, readlen, httpbodylen); } rsp->code = 200; return http_send_response(rsp); }
void HashInsert(void *entry,unsigned int key,Hash hash) { HashEntry ent; int j; assert(3,!HashLookup(key,hash)); j = (hash->mapfunc)(key); ent = (HashEntry) localmalloc(sizeof(*ent)); ent->next = hash->array[j]; hash->array[j]=ent; ent->key = key; ent->entry = entry; }
int handle_http_propfind(http_req * req, http_rsp * rsp) { int ret = OK; HashElement * e = NULL; int depth = -1; HashHandle props = NULL_HANDLE; CacheHandle cache = NULL_HANDLE; char * propxml = NULL; int contentlen = 0; char * vpath = req->uri; struct stat buf; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif if(OK != Webdav_CheckPath(req->uri)) { WEBLOG_ERROR("<%s> PROPFIND is not allowed for non-webdav path [%s].\n", __FUNCTION__, req->uri); handle_http_error(403, req, rsp); ret = NG; goto __error_out; } if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } WEBLOG_INFO("<%s> stat the file \"%s\".\n", __FUNCTION__, vpath); ret = stat(vpath, &buf); /* Check if statistics are valid: */ if(ret != 0) { WEBLOG_ERROR("<%s> fail to stat the file \"%s\".\n", __FUNCTION__, vpath); switch (errno) { case ENOENT: WEBLOG_ERROR("<%s> File %s not found.\n", __FUNCTION__, vpath); handle_http_error(404, req, rsp); ret = NG; goto __error_out; case EINVAL: /* no break */ default: /* Should never be reached. */ WEBLOG_ERROR("<%s> Unexpected error in _stat.\n", __FUNCTION__); handle_http_error(500, req, rsp); ret = NG; goto __error_out; } } props = HashTableCreate(64); ASSERT(props != NULL_HANDLE); /* get depth. */ e = HashLookup(req->headOptions, "Depth"); if(!e) depth = -1; else if(e->value.data.string[0] == '0') depth = 0; else if(e->value.data.string[0] == '1') depth = 1; else depth = -1; if(depth == -1 && TRUE == Webdav_isFolder(vpath)) { WEBLOG_ERROR("<%s> PROPFIND a collection with infinite depth is not allowed.\n", __FUNCTION__); handle_http_error(403, req, rsp); ret = NG; goto __error_out; } #ifdef WEBCFG_MINIMIZE_SERVER #else e = HashLookup(req->headOptions, "Content-Type"); if(e && strstr(e->value.data.string, "xml")) { char * xmlsockbuf = NULL; char strbuf[128] = {0}; char *end, *p, *q; HashValue eeee = HashString("", FALSE); // empty value! WEBLOG_INFO("<%s> Client request props in a xml body.\n", __FUNCTION__); e = HashLookup(req->headOptions, "Content-Length"); if(!e) { /* RFC2616, 14.23. */ WEBLOG_ERROR("<%s> Missing \"Content-Length\" for xml body.\n", __FUNCTION__); handle_http_error(400, req, rsp); ret = NG; goto __error_out; } contentlen = atoi(e->value.data.string); xmlsockbuf = (char *)webmalloc(contentlen+1); memset(xmlsockbuf, 0, contentlen+1); if(req->datalen > 0) // data left in head buffer. { memcpy(xmlsockbuf, req->sockbuf, req->datalen); WEBLOG_VERBOSE("<%s> previous buffered %d/%d bytes consumed.\n", __FUNCTION__, req->datalen, contentlen); } /* if there's more data in socket.... */ if (req->datalen < contentlen) { /* read rest of data from socket. */ p = xmlsockbuf + req->datalen; req->datalen = recv(req->sock, p, contentlen-req->datalen, 0); WEBLOG_VERBOSE("<%s> %d/%d bytes read from socket.\n", __FUNCTION__, req->datalen, contentlen); dumpText(xmlsockbuf, contentlen); } p = strstr(xmlsockbuf, "<prop>") + 6; end = strstr(xmlsockbuf, "</prop>"); if(strstr(xmlsockbuf, "<allprop/>")) { WEBLOG_INFO("<%s> client request all props.\n", __FUNCTION__); } else { ASSERT(p<end); *end = '\0'; /* good for str api. */ /* Possible Value: WinXP: <propname/> Cadaver: <propname xmlns="DAV:"/> */ do { p = strchr(p, '<'); if(!p) break; else p++; q = strstr(p, "/>"); ASSERT(q && (q-p < sizeof(strbuf))); strncpy(strbuf, p, q-p); p = strchr(strbuf, ' '); if(p) *p = '\0'; p = strtrim(strbuf); WEBLOG_INFO("<%s> client request prop: <%s>\n", __FUNCTION__, p); HashAdd(props, p, eeee); p = q + 2; } while(p<end); /* <xxx/>\r\n</prop> */ } } #endif cache = CacheCreate(); Webdav_Props(props, cache, vpath, depth); contentlen = CacheGetData(cache, &propxml); ASSERT(propxml); dumpText(propxml, contentlen); WEBLOG_INFO("<%s> response xml ready. len %d.\n", __FUNCTION__, contentlen); rsp->code = 207; rsp->body = propxml; http_add_rspoption(rsp, "Content-Type", "text/xml"); http_send_response(rsp); __error_out: if (props != NULL_HANDLE) HashTableDestroy(props); if (cache != NULL_HANDLE) CacheDestroy(cache); return ret; }
int handle_http_put(http_req * req, http_rsp * rsp) { HashElement * e = NULL; char * vpath = NULL; int httpbodylen = 0; int readlen = 0; FILE * fp = NULL; int i = 0; unsigned char * buffer = NULL; int buflen = 1024*1024; char strbuf[128] = {0}; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif vpath = req->uri; ASSERT(vpath && vpath[0]); if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } e = HashLookup(req->headOptions, "Content-Length"); if(!e) { /* RFC2616, 14.23. */ WEBLOG_ERROR("<%s> Missing \"Content-Length\" in POST/PUT.\n", __FUNCTION__); return handle_http_error(400, req, rsp); } httpbodylen = atoi(e->value.data.string); WEBLOG_INFO("<%s> Content-Length:%d.\n", __FUNCTION__, httpbodylen); if(OK != Webdav_CheckPath(vpath)) return handle_http_error(501, req, rsp); if(WEBDAVR_OK != Webdav_CreateFile(vpath)) return handle_http_error(501, req, rsp); /* read data from socket and save it into target file. */ fp = fopen(vpath, "wb"); if(!fp) return handle_http_error(501, req, rsp); if(req->datalen > 0) // data left in head buffer. { i = fwrite(req->sockbuf, 1, req->datalen, fp); ASSERT(i == req->datalen); WEBLOG_VERBOSE("<%s> write previous buffered %d bytes into %s.\n", __FUNCTION__, req->datalen, vpath); readlen += req->datalen; } /* if there's more data in socket.... req->sockbuf is too small for large files. */ do { buflen /= 2; buffer = (char *)webmalloc(buflen); } while(!buffer); while(readlen < httpbodylen) { req->datalen = recv(req->sock, buffer, buflen, 0); if(req->datalen < 0) { print_socket_error(); break; } else if(req->datalen == 0) { WEBLOG_INFO("<%s> client closed. data progress: %d/%d.\n", __FUNCTION__, readlen, httpbodylen); break; } readlen += req->datalen; WEBLOG_VERBOSE("<%s> progress: %10d/%d, ", __FUNCTION__, readlen, httpbodylen); i = fwrite(buffer, 1, req->datalen, fp); WEBLOG_VERBOSE("R %d <- socket, W %d -> %s.\n", req->datalen, i, vpath); ASSERT(i == req->datalen); } rsp->code = 201; e = HashLookup(req->headOptions, "Host"); if(!e) { /* RFC2616, 14.23. */ WEBLOG_ERROR("<%s> Missing \"Host\" in POST/PUT.\n", __FUNCTION__); sprintf(strbuf, "/webdav%s", vpath); } else { sprintf(strbuf, "http://%s/webdav%s", e->value.data.string, vpath); } http_add_rspoption(rsp, "Location", strbuf); http_send_response(rsp); /****************************** Double Confirm File Size! *******************************/ fseek(fp, 0, SEEK_END); i = ftell(fp); WEBLOG_INFO("<%s> Double Confirm. file-size: %d. content-length: %d.\n", __FUNCTION__, i, httpbodylen); ASSERT(i == httpbodylen); webfree(buffer); fclose(fp); return OK; }
int handle_http_get(http_req * req, http_rsp * rsp) { int ret = OK; HashElement * e = NULL; /* ------------------------------------ */ FILE * fp = NULL; char * timebuf = NULL; /* ------------------------------------ */ size_t total_length = 0; /* total length of the file. */ size_t task_length = 0; /* requested length. */ char strbuf[64] = {0}; size_t from = -1; size_t to = -1; char path[256] = {0}; char * vpath = path; struct stat buf; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif vpath = req->uri; ASSERT(vpath && vpath[0]); ASSERT(rsp->headOptions != NULL_HANDLE); if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } /* Make sure the requesting URI is authorized. */ if(strstr(vpath, "..") || strstr(vpath, "./")) return handle_http_error(403, req, rsp); /* Check if the requesting URI is a directory. */ WEBLOG_INFO("<%s> stat the file \"%s\".\n", __FUNCTION__, vpath); ret = web_stat(vpath, &buf); /* Check if statistics are valid: */ if(ret != 0) { WEBLOG_ERROR("<%s> fail to stat the file \"%s\".\n", __FUNCTION__, vpath); switch (errno) { case ENOENT: WEBLOG_ERROR("<%s> File %s not found.\n", __FUNCTION__, vpath); return handle_http_error(404, req, rsp); case EINVAL: /* no break */ default: /* Should never be reached. */ WEBLOG_ERROR("<%s> Unexpected error in _stat.\n", __FUNCTION__); return handle_http_error(500, req, rsp); } } else { WEBLOG_INFO("<%s> File size : "sizett"\n", __FUNCTION__, buf.st_size ); //WEBLOG_INFO("<%s> Drive : %c:\n", __FUNCTION__, buf.st_dev + 'A' ); timebuf = ctime(&buf.st_mtime); WEBLOG_INFO("<%s> Time modified : %s", __FUNCTION__, timebuf); if(S_IFDIR & buf.st_mode) { #if 1 //#ifdef WEBCFG_SUPPORT_WEBDAV CacheHandle cache = CacheCreate(); if (NULL_HANDLE == cache) return handle_http_error(500, req, rsp); rsp->code = 200; web_lsdir(cache, vpath); http_add_rspoption(rsp, "Content-Type", "text/html; charset=\"utf-8\""); CacheGetData(cache, &rsp->body); http_send_response(rsp); if (cache != NULL_HANDLE) CacheDestroy(cache); return OK; #else WEBLOG_INFO("<%s> client requesting a directory!\n", __FUNCTION__); return handle_http_error(403, req, rsp); #endif } } #ifdef WEBCFG_SUPPORT_HTTPTIME /* RFC2616, 14.25. If-Modified-Since */ e = HashLookup(req->headOptions, "If-Modified-Since"); if(e) { time_t reqtime, acctime; ASSERT(e->value.type == eHashString); reqtime = get_http_time(e->value.data.string); acctime = get_http_time(timebuf); //WEBLOG_INFO("<%s> reqtime=[%u] vs [%u]=acctime\n", __FUNCTION__, reqtime, acctime); if(reqtime >= acctime) { rsp->code = 304; rsp->body = using_customized_body; // 304 has no body. http_add_rspoption(rsp, "Content-Length", "0"); return http_send_response(rsp); } } #endif fp = web_fopen(vpath,"rb"); WEBLOG_INFO("<%s> fopen(%s) == %p \n", __FUNCTION__, vpath, fp); if(!fp) { WEBLOG_ERROR("<%s> failed to open file \"%s\" %s \n", __FUNCTION__, vpath, strerror(errno)); return handle_http_error(500, req, rsp); } ASSERT(fp); /* check if fp is NULL. */ fseek(fp, 0, SEEK_END); total_length = ftell(fp); fseek(fp, 0, SEEK_SET); #ifdef WEBCFG_SUPPORT_HTTPRANGE /* handle range request */ e = HashLookup(req->headOptions, "Range"); if(e) { char * p = e->value.data.string; ASSERT(e->value.type == eHashString); WEBLOG_INFO("<%s> client range request: %s\n", __FUNCTION__, p); /* figure out FROM-TO */ if(0 == strncmp(p, " bytes=-", 8)) { sscanf(p," bytes=-"sizett"", &task_length); from = total_length-task_length; to = total_length-1; } else { sscanf(p," bytes="sizett"-"sizett"", &from, &to); if(to < 0) { task_length = total_length - from; to = total_length-1; } else { task_length = to - from + 1; } } WEBLOG_INFO("<%s> request "sizett"-"sizett", total "sizett", we have "sizett".\n", __FUNCTION__, from, to, task_length, total_length); if(from < 0 || to < 0 || to >= total_length || from >= total_length || from > to) { http_add_rspoption(rsp, "Accept-Ranges", "bytes"); //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri)); http_add_rspoption(rsp, "Content-Range", "*/*"); return handle_http_error(416, req, rsp); } else { rsp->code = 206; rsp->body = using_customized_body; http_add_rspoption(rsp, "Accept-Ranges", "bytes"); //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri)); sprintf(strbuf, "bytes "sizett"-"sizett"/"sizett"", from, to, total_length); http_add_rspoption(rsp, "Content-Range", strbuf); sprintf(strbuf, sizett, task_length); http_add_rspoption(rsp, "Content-Length", strbuf); http_send_response(rsp); } } else #endif /* WEBCFG_SUPPORT_HTTPRANGE */ { from = 0; task_length = total_length; to = total_length-1; sprintf(strbuf, sizett, task_length); rsp->code = 200; rsp->body = using_customized_body; #ifdef WEBCFG_SUPPORT_HTTPRANGE http_add_rspoption(rsp, "Accept-Ranges", "bytes"); #endif //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri)); http_add_rspoption(rsp, "Content-Length", strbuf); http_send_response(rsp); } ret = OK; /* Respond with data. For HEAD request, skip this. */ if(HTTP_GET == req->method) { size_t i = 0; size_t buflen = 1024*1024; size_t readsize = 0; size_t counter = 0; char * buffer = NULL; #define SPEED_REPORT #ifdef SPEED_REPORT /* speed test */ //size_t data_1 = 0, data_2 = 0; time_t time_1 = time(NULL), time_2; #endif do { buflen /= 2; buffer = (char *)webmalloc(buflen); } while(!buffer); fseek(fp, from, SEEK_SET); while(1) { memset(buffer, 0, buflen); if(task_length-counter > buflen) readsize=fread(buffer, 1, buflen, fp); else readsize=fread(buffer, 1, task_length-counter, fp); if(readsize <= 0) { WEBLOG_ERROR("<%s> fread fail "sizett". %s.\n", __FUNCTION__, readsize, strerror(socketGetError())); ret = NG; break; } WEBLOG_VERBOSE("<%s> read "sizett" from %s, sent "sizett" to socket.\n ", __FUNCTION__, readsize, vpath, i); i = WebWrite(req->sock, buffer, readsize); if(i != readsize) { WEBLOG_ERROR("<%s> WebWrite fail "sizett". %s.\n", __FUNCTION__, i, strerror(socketGetError())); ret = NG; break; } //ASSERT(i==readsize); counter += readsize; #ifdef SPEED_REPORT time_2 = time(NULL); if (time_2 - time_1 > 1) WEBLOG_VERBOSE("<%s> "sizett"KB/s\n", __FUNCTION__, counter/1024/(time_2-time_1)); #endif WEBLOG_VERBOSE("<%s> "sizett"/"sizett"\n", __FUNCTION__, counter, task_length); if(counter >= task_length) break; } webfree(buffer); } if(fp) fclose(fp); return ret; }
int http_send_response(http_rsp * rsp) { CacheHandle cache = NULL_HANDLE; char * datapointer = NULL; int datalength = 0; char strbuf[64] = {0}; char bodybuf[256] = {0}; HashElement * e = NULL; http_status * stt = get_http_status(rsp->code); WEBLOG_API(); ASSERT(stt); if(using_customized_body != rsp->body) { /* if body is empty, make a default body. */ if(!rsp->body) { WEBLOG_VERBOSE("<%s> body empty. add default body.\n", __FUNCTION__); sprintf(bodybuf, "<HTML><BODY><b>%s</b></BODY></HTML>", stt->s_name); rsp->body = bodybuf; http_add_rspoption(rsp, "Content-Type", "text/html"); } /* if Content-Length is not given, try caculating it here. */ if(!HashLookup(rsp->headOptions, "Content-Length")) { if(rsp->body) sprintf(strbuf, sizett, strlen(rsp->body)); else sprintf(strbuf, "%d", 0); http_add_rspoption(rsp, "Content-Length", strbuf); } } /* server info is always present. */ http_add_rspoption(rsp, "Server", SERVER_VER); #ifdef WEBCFG_SUPPORT_HTTPRANGE http_add_rspoption(rsp, "Accept-Ranges", "bytes"); #endif if(NULL_HANDLE == cache) cache = CacheCreate(); ASSERT(NULL_HANDLE != cache); CacheClean(cache); /* send first line! */ CacheWriteString(cache, "HTTP/1.1 "); CacheWriteString(cache, stt->s_code); CacheWriteString(cache, " "); CacheWriteString(cache, stt->s_name); CacheWriteString(cache, "\r\n"); //HashDump(rsp->headOptions); /* send head options! */ e = HashFirst(rsp->headOptions); while(e) { CacheWriteString(cache, e->name); CacheWriteString(cache, ": "); if(e->value.type == eHashString) { CacheWriteString(cache, e->value.data.string); } else if(e->value.type == eHashInt) { sprintf(strbuf, "%d", e->value.data.integer); CacheWriteString(cache, strbuf); } CacheWriteString(cache, "\r\n"); e = HashNext(rsp->headOptions, e); } CacheWriteString(cache, "\r\n"); /* send body */ if(rsp->body && rsp->body != using_customized_body) CacheWriteString(cache, rsp->body); datalength = CacheGetData(cache, &datapointer); ASSERT(datapointer && datalength > 0); WebWrite(rsp->sock, datapointer, datalength); CacheDestroy(cache); return OK; }
int handle_http_move(http_req * req, http_rsp * rsp) { int ret = 0; char * from = NULL; char * to = NULL; char * tooooo = NULL; char * host = NULL; HashElement * e = NULL; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif from = req->uri; ASSERT(from && from[0]); if(0 == strlen(from)) { strcat(from, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, from); } e = HashLookup(req->headOptions, "Destination"); if(!e) { WEBLOG_ERROR("<%s> Missing \"Destination\" in Move/Copy.\n", __FUNCTION__); return handle_http_error(400, req, rsp); } ASSERT(e->value.type == eHashString); to = e->value.data.string; e = HashLookup(req->headOptions, "Host"); ASSERT(e); // static int _simple_validation(http_req * req) host = e->value.data.string; /* example To: [http://x.x.x.x:y/webdav/1.txt] Host: [x.x.x.x:y] */ tooooo = to + 7 + strlen(host); // 7 for "http://" if(0 == strlen(tooooo)) { strcat(from, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, tooooo); } url_decode(tooooo); WEBLOG_INFO("<%s> %s from %s to %s.\n", __FUNCTION__, (HTTP_MOVE == req->method)?"Move":"Copy", from, tooooo); e = HashLookup(req->headOptions, "Overwrite"); if(e && e->value.data.string[0] == 'T') { if(HTTP_MOVE == req->method) ret = Webdav_Move(from, tooooo, TRUE); else ret = Webdav_Copy(from, tooooo, TRUE); } else { if(HTTP_MOVE == req->method) ret = Webdav_Move(from, tooooo, FALSE); else ret = Webdav_Copy(from, tooooo, FALSE); } switch(ret) { case WEBDAVR_OK: rsp->code = 201; http_add_rspoption(rsp, "Location", to); http_send_response(rsp); break; default: handle_http_error(502, req, rsp); break; } return OK; }
int handle_http_proppatch(http_req * req, http_rsp * rsp) { HashElement * e = NULL; char * propxml = NULL; int contentlen = 0; char * vpath = req->uri; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif if(OK != Webdav_CheckPath(req->uri)) { WEBLOG_ERROR("<%s> PROPFIND is not allowed for non-webdav path [%s].\n", __FUNCTION__, req->uri); return handle_http_error(403, req, rsp); } if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } #ifdef WEBCFG_MINIMIZE_SERVER #else if(OK != Webdav_CheckPath(req->uri)) { WEBLOG_ERROR("<%s> PROPFIND is not allowed for non-webdav path [%s].\n", __FUNCTION__, req->uri); return handle_http_error(403, req, rsp); } e = HashLookup(req->headOptions, "Content-Type"); if(e && strstr(e->value.data.string, "xml")) { char * xmlsockbuf = NULL; char * p = NULL; WEBLOG_INFO("<%s> Client provide props value in a xml body.\n", __FUNCTION__); e = HashLookup(req->headOptions, "Content-Length"); if(!e) { /* RFC2616, 14.23. */ WEBLOG_ERROR("<%s> Missing \"Content-Length\" for xml body.\n", __FUNCTION__); return handle_http_error(400, req, rsp); } contentlen = atoi(e->value.data.string); xmlsockbuf = (char *)webmalloc(contentlen+1); memset(xmlsockbuf, 0, contentlen+1); if(req->datalen > 0) // data left in head buffer. { memcpy(xmlsockbuf, req->sockbuf, req->datalen); WEBLOG_VERBOSE("<%s> previous buffered %d/%d bytes consumed.\n", __FUNCTION__, req->datalen, contentlen); } /* if there's more data in socket.... */ if (req->datalen < contentlen) { /* read rest of data from socket. */ p = xmlsockbuf + req->datalen; req->datalen = recv(req->sock, p, contentlen-req->datalen, 0); WEBLOG_VERBOSE("<%s> %d/%d bytes read from socket.\n", __FUNCTION__, req->datalen, contentlen); dumpText(xmlsockbuf, contentlen); } } #endif return handle_http_error(501, req, rsp); }