int handle_http_mkcol(http_req * req, http_rsp * rsp) { char * vpath = 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 vpath = req->uri; ASSERT(vpath && vpath[0]); if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } if(OK != Webdav_CheckPath(vpath)) return handle_http_error(403, req, rsp); if(WEBDAVR_OK != Webdav_CreateFolder(vpath)) return handle_http_error(403, req, rsp); rsp->code = 201; return http_send_response(rsp); }
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); }
int handle_http_delete(http_req * req, http_rsp * rsp) { char * vpath = NULL; int ret = 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); } if(OK != Webdav_CheckPath(vpath)) { return handle_http_error(403, req, rsp); } /* Note that the path can be either a folder, or a file. If it is a folder, it can be either empty, or with files. */ if(TRUE == Webdav_isFolder(vpath)) ret = Webdav_DeleteFolder(vpath); else ret = Webdav_DeleteFile(vpath); if(WEBDAVR_OK == ret) { rsp->code = 204; return http_send_response(rsp); } else { WEBLOG_INFO("<%s> Failed to remove %s.\n", __FUNCTION__, vpath); return handle_http_error(403, req, rsp); } }
static void on_read_cb(uv_stream_t *stream, ssize_t nread, uv_buf_t buf) { Connection *conn = (Connection*) stream; assert(conn->read_clear == false); if (nread < 0) { // // XXX: Do we have to call uv_read_stop(), or is it implicit? // // on_read_cb will never be called again for this connection, so we don't // have to reset anything. // uv_close((uv_handle_t*) conn, on_close_cb); } else if (nread > 0) { conn->read_buffer.increase_size(nread); conn->read_clear = true; if (conn->in_body) { // We are reading in the body. No need to call the parser! handle_http_body(conn); } else { conn->parse_offset = http_parser_run(&conn->parser, &conn->req, conn->read_buffer.data(), conn->read_buffer.size(), conn->parse_offset); if (http_parser_is_finished(&conn->parser)) { handle_http_header_parsed(conn); } else if (http_parser_has_error(&conn->parser)) { handle_http_error(conn); } } } else { // // This happens when libuv calls alloc_read_buffer, but does not need the buffer. // We don't have to free the buffer, as it is part of the connection. // assert(nread == 0); conn->read_clear = true; } }
static void HttpProtocol_on_error(Protocol *prot, DWORD error) { HttpProtocol *This = impl_from_Protocol(prot); HRESULT hres; TRACE("(%p) %d\n", prot, error); if(prot->flags & FLAG_FIRST_CONTINUE_COMPLETE) { FIXME("Not handling error %d\n", error); return; } while((hres = handle_http_error(This, error)) == RPC_E_RETRY) { error = send_http_request(This); if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS) return; } protocol_abort(prot, hres); protocol_close_connection(prot); return; }
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_connect(http_req * req, http_rsp * rsp) { WEBLOG_API(); return handle_http_error(501, req, rsp); }
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 handle_http_unlock(http_req * req, http_rsp * rsp) { WEBLOG_API(); return handle_http_error(501, req, rsp); }
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); }
static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD request_flags, HINTERNET internet_session, IInternetBindInfo *bind_info) { HttpProtocol *This = impl_from_Protocol(prot); WCHAR *addl_header = NULL, *post_cookie = NULL, *rootdoc_url = NULL; IServiceProvider *service_provider = NULL; IHttpNegotiate2 *http_negotiate2 = NULL; BSTR url, host, user, pass, path; LPOLESTR accept_mimes[257]; const WCHAR **accept_types; BYTE security_id[512]; DWORD len, port, flags; ULONG num, error; BOOL res, b; HRESULT hres; static const WCHAR wszBindVerb[BINDVERB_CUSTOM][5] = {{'G','E','T',0}, {'P','O','S','T',0}, {'P','U','T',0}}; hres = IUri_GetPort(uri, &port); if(FAILED(hres)) return hres; hres = IUri_GetHost(uri, &host); if(FAILED(hres)) return hres; hres = IUri_GetUserName(uri, &user); if(SUCCEEDED(hres)) { hres = IUri_GetPassword(uri, &pass); if(SUCCEEDED(hres)) { This->base.connection = InternetConnectW(internet_session, host, port, user, pass, INTERNET_SERVICE_HTTP, This->https ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)&This->base); SysFreeString(pass); } SysFreeString(user); } SysFreeString(host); if(FAILED(hres)) return hres; if(!This->base.connection) { WARN("InternetConnect failed: %d\n", GetLastError()); return INET_E_CANNOT_CONNECT; } num = 0; hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_ROOTDOC_URL, &rootdoc_url, 1, &num); if(hres == S_OK && num) { FIXME("Use root doc URL %s\n", debugstr_w(rootdoc_url)); CoTaskMemFree(rootdoc_url); } num = sizeof(accept_mimes)/sizeof(accept_mimes[0])-1; hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_ACCEPT_MIMES, accept_mimes, num, &num); if(hres == INET_E_USE_DEFAULT_SETTING) { static const WCHAR default_accept_mimeW[] = {'*','/','*',0}; static const WCHAR *default_accept_mimes[] = {default_accept_mimeW, NULL}; accept_types = default_accept_mimes; num = 0; }else if(hres == S_OK) { accept_types = (const WCHAR**)accept_mimes; }else { WARN("GetBindString BINDSTRING_ACCEPT_MIMES failed: %08x\n", hres); return INET_E_NO_VALID_MEDIA; } accept_mimes[num] = 0; if(This->https) request_flags |= INTERNET_FLAG_SECURE; hres = IUri_GetPathAndQuery(uri, &path); if(SUCCEEDED(hres)) { This->base.request = HttpOpenRequestW(This->base.connection, This->base.bind_info.dwBindVerb < BINDVERB_CUSTOM ? wszBindVerb[This->base.bind_info.dwBindVerb] : This->base.bind_info.szCustomVerb, path, NULL, NULL, accept_types, request_flags, (DWORD_PTR)&This->base); SysFreeString(path); } while(num--) CoTaskMemFree(accept_mimes[num]); if(FAILED(hres)) return hres; if (!This->base.request) { WARN("HttpOpenRequest failed: %d\n", GetLastError()); return INET_E_RESOURCE_NOT_FOUND; } hres = IInternetProtocolSink_QueryInterface(This->base.protocol_sink, &IID_IServiceProvider, (void **)&service_provider); if (hres != S_OK) { WARN("IInternetProtocolSink_QueryInterface IID_IServiceProvider failed: %08x\n", hres); return hres; } hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate, &IID_IHttpNegotiate, (void **)&This->http_negotiate); if (hres != S_OK) { WARN("IServiceProvider_QueryService IID_IHttpNegotiate failed: %08x\n", hres); IServiceProvider_Release(service_provider); return hres; } hres = IUri_GetAbsoluteUri(uri, &url); if(FAILED(hres)) { IServiceProvider_Release(service_provider); return hres; } hres = IHttpNegotiate_BeginningTransaction(This->http_negotiate, url, default_headersW, 0, &addl_header); SysFreeString(url); if(hres != S_OK) { WARN("IHttpNegotiate_BeginningTransaction failed: %08x\n", hres); IServiceProvider_Release(service_provider); return hres; } len = addl_header ? strlenW(addl_header) : 0; This->full_header = heap_alloc(len*sizeof(WCHAR)+sizeof(default_headersW)); if(!This->full_header) { IServiceProvider_Release(service_provider); return E_OUTOFMEMORY; } if(len) memcpy(This->full_header, addl_header, len*sizeof(WCHAR)); CoTaskMemFree(addl_header); memcpy(This->full_header+len, default_headersW, sizeof(default_headersW)); hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2, &IID_IHttpNegotiate2, (void **)&http_negotiate2); IServiceProvider_Release(service_provider); if(hres != S_OK) { WARN("IServiceProvider_QueryService IID_IHttpNegotiate2 failed: %08x\n", hres); /* No goto done as per native */ }else { len = sizeof(security_id)/sizeof(security_id[0]); hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, security_id, &len, 0); IHttpNegotiate2_Release(http_negotiate2); if (hres != S_OK) WARN("IHttpNegotiate2_GetRootSecurityId failed: %08x\n", hres); } /* FIXME: Handle security_id. Native calls undocumented function IsHostInProxyBypassList. */ if(This->base.bind_info.dwBindVerb == BINDVERB_POST) { num = 0; hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_POST_COOKIE, &post_cookie, 1, &num); if(hres == S_OK && num) { if(!InternetSetOptionW(This->base.request, INTERNET_OPTION_SECONDARY_CACHE_KEY, post_cookie, lstrlenW(post_cookie))) WARN("InternetSetOption INTERNET_OPTION_SECONDARY_CACHE_KEY failed: %d\n", GetLastError()); CoTaskMemFree(post_cookie); } } flags = INTERNET_ERROR_MASK_COMBINED_SEC_CERT; res = InternetSetOptionW(This->base.request, INTERNET_OPTION_ERROR_MASK, &flags, sizeof(flags)); if(!res) WARN("InternetSetOption(INTERNET_OPTION_ERROR_MASK) failed: %u\n", GetLastError()); b = TRUE; res = InternetSetOptionW(This->base.request, INTERNET_OPTION_HTTP_DECODING, &b, sizeof(b)); if(!res) WARN("InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %u\n", GetLastError()); do { error = send_http_request(This); switch(error) { case ERROR_IO_PENDING: return S_OK; case ERROR_SUCCESS: /* * If sending response ended synchronously, it means that we have the whole data * available locally (most likely in cache). */ return protocol_syncbinding(&This->base); default: hres = handle_http_error(This, error); } } while(hres == RPC_E_RETRY); WARN("HttpSendRequest failed: %d\n", error); return hres; }