void HttpReqImpl::useHTTP11(bool use) { httpMinVer = use ? 1 : 0; useChunked = use; if (use == false) closeConn = true; else { HeaderValue h = getHeaderField(fldConnection); if (h.defined && h == "close") closeConn = true; else closeConn = false; } }
void Http::update(float delta) { switch (m_state) { case STATE_NONE: break; case STATE_INIT: { m_socket = socket(AF_INET, SOCK_STREAM, 0); if(m_socket == INVALID_SOCKET) { DEBUG_PRINT("[HTTP] socket error. %d", WSAGetLastError()); m_state = STATE_ERROR; break; } if (ioctlsocket(m_socket, FIONBIO, &m_noblockingmode)) { DEBUG_PRINT("[HTTP] socket error %d\n", WSAGetLastError()); m_state = STATE_ERROR; break; } struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_INET; int err; if ((err = getaddrinfo(m_address.c_str(), NULL, &hints, &m_addInfo))) { DEBUG_PRINT("[HTTP] addinfo error %d\n", err); m_state = STATE_ERROR; break; } m_state = STATE_CONNECT; break; } case STATE_CONNECT: { if (!m_addInfo) { m_state = STATE_ERROR; } else { struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(m_port); // addr.sin_addr.S_un.S_addr = inet_addr(m_address.c_str()); addr.sin_addr.S_un = ((struct sockaddr_in *)(m_addInfo->ai_addr))->sin_addr.S_un; DEBUG_PRINT("[HTTP] request address \"%s\"(%s)\n", m_address.c_str(), inet_ntoa(addr.sin_addr)); if (connect(m_socket, (struct sockaddr *)&addr, sizeof(addr))) { DEBUG_PRINT("[HTTP] connect error %d\n", WSAGetLastError()); m_state = STATE_ERROR; } else { m_state = STATE_SEND_REQUEST; } } break; } case STATE_SEND_REQUEST: { std::stringstream send_request; switch (m_method) { case METHOD_GET: send_request << "GET " << m_path << " HTTP/1.0\r\n"; break; case METHOD_POST: send_request << "POST " << m_path << " HTTP/1.0\r\n"; break; default: ASSERT_MES(false, "[HTTP] invalid method. method=%d\n", m_method); } send_request << "Host: " << m_address << "\r\n"; if (!m_basicAuth.empty()) { send_request << "Authorization: Basic " << m_basicAuth << "\r\n"; } send_request << "\r\n"; DEBUG_PRINT("[HTTP] send request = \"%s\"\n", send_request.str().c_str()); int n = send(m_socket, send_request.str().c_str(), send_request.str().size(), 0); if (n < 0) { DEBUG_PRINT("[HTTP] send error %d\n", WSAGetLastError()); m_state = STATE_ERROR; } else { m_state = STATE_RECIEVE_WAIT; } break; } case STATE_RECIEVE_WAIT: { char buf[RECV_BUFFER_SIZE]; memset(buf, 0, sizeof(buf)); int n = recv(m_socket, buf, sizeof(buf)-1, 0); if (n < 0) { if (WSAGetLastError() != WSAEWOULDBLOCK) { DEBUG_PRINT("[HTTP] recieve error : 0x%x\n", WSAGetLastError()); m_state = STATE_ERROR; } } else { DEBUG_PRINT("[HTTP] recieve start.\n"); buf[n] = '\0'; // ヘッダのみ切り離す char* p = strstr(buf, "\r\n\r\n"); if (p) { // ヘッダの終端が含まれていた p += strlen("\r\n"); // 改行が最後に入るように *p = '\0'; m_header = buf; // リクエストボディ p += strlen("\r\n"); int bodysize = n-(p-buf); if (bodysize > 0) { m_data.resize(bodysize); memcpy(&m_data[0], p, bodysize); } m_isRecvData = true; DEBUG_PRINT("[HTTP] header end\n"); } else { // ヘッダ終わっていない m_header = buf; m_isRecvData = false; } m_state = STATE_RECIEVE; } break; } case STATE_RECIEVE: { char buf[RECV_BUFFER_SIZE]; memset(buf, 0, sizeof(buf)); int n = recv(m_socket, buf, sizeof(buf)-1, 0); if (n == 0) { m_state = STATE_RECIEVE_END; } else if (n < 0) { if (WSAGetLastError() != WSAEWOULDBLOCK) { DEBUG_PRINT("[HTTP] recieve error : 0x%x\n", WSAGetLastError()); m_state = STATE_ERROR; } } else { buf[n] = '\0'; // DEBUG_PRINT(buf); if (m_isRecvData) { RecvData::size_type size = m_data.size(); m_data.resize(size+n); memcpy(&m_data[size], buf, n); } else { char* p = strstr(buf, "\r\n\r\n"); if (p) { // ヘッダの終端が含まれていた p += strlen("\r\n"); // 改行が最後に入るように *p = '\0'; m_header += buf; // リクエストボディ p += strlen("\r\n"); int bodysize = n-(p-buf); m_data.resize(bodysize); memcpy(&m_data[0], p, bodysize); m_isRecvData = true; DEBUG_PRINT("[HTTP] header end\n"); } else { // 先頭が改行コードなら追加 p = buf; while(*p == '\r' || *p == '\n') { m_header += *p; p++; } std::string::size_type pos = m_header.find("\r\n\r\n"); if (pos == std::string::npos) { // ヘッダ終わっていない m_header += p; } else { // 連結した結果ヘッダ終わってた m_header.erase(pos+strlen("\r\n")); // 改行が最後に入るように int bodysize = n-(p-buf); if (bodysize > 0) { m_data.resize(bodysize); memcpy(&m_data[0], p, bodysize); } m_isRecvData = true; DEBUG_PRINT("[HTTP] header end\n"); } } } } break; } case STATE_RECIEVE_END: { close(); parseHeader(); const char* content_type = getHeaderField("Content-Type"); // Content-Type が text/*** なら'\0'追加 if (content_type) { if (strncmp(content_type, "text/", strlen("text/")) == 0) { m_data.push_back('\0'); } } m_state = STATE_FINISH; DEBUG_PRINT("[HTTP] recieve end.\n"); break; } case STATE_FINISH: { break; } case STATE_ERROR: { close(); m_state = STATE_FINISH; m_header.clear(); m_data.clear(); DEBUG_PRINT("[HTTP] error end.\n"); break; } default: ASSERT_MES(false, "[HTTP] state invalid. state=%d\n", m_state); } }
ITCPServerConnHandler::Command HttpReqImpl::finishReadHeader() { TextParser<char,StaticAlloc<256> > parser; //open output and input, we need stream to show error pages outputClosed = false; inputClosed = false; isHeadMethod = ConstStrA(method) == "HEAD"; closeConn = httpMinVer == 0; //check connection HeaderValue strconn = getHeaderField(fldConnection); if (strconn.defined) { if (strconn == "close") closeConn = true; } //check content length HeaderValue strsize = getHeaderField(fldContentLength); if (strsize.defined && parser(" %u1 ", strsize)) { remainPostData = parser[1]; } else { remainPostData = 0; } //check chunked POST HeaderValue strchunked = getHeaderField(fldTransferEncoding); if (strchunked.defined != 0 && strchunked == "chunked") { chunkedPost = true; remainPostData = 0; //remainPostData is used to count chunks } else { chunkedPost = false; } //check expectation for 100-continue HeaderValue strexpect = getHeaderField(fldExpect); if (strexpect.defined != 0) { if (strexpect == "100-continue" || strexpect == "100-Continue") { bNeedContinue = true; } else { return errorPageKA(417); } } else { bNeedContinue = false; } //check host ConstStrA vpath = path; host = getHeaderField(fldHost); if (!mapHost(host, vpath)) { return errorPageKA(404); } if (vpath.empty()) { redirect("+/"); return processHandlerResponse(0); } //find handler IHttpHandler *h; curHandler = nil; natural res = callHandler( vpath, &h); if (h == 0) return errorPageKA(404); if (curHandler == nil) curHandler = h; //need this to correctly handle forward function return processHandlerResponse(res); }
HeaderValue HttpReqImpl::getHeaderField(HeaderField field) const { return getHeaderField(getHeaderFieldName(field)); }
/* This function operates for the purposes of the proxy server. When a * request arrives from a client configured to use the proxy, the path * after GET will be absolute. The proxy will strip out this absolute * request and replace it with a relative request. This function strips * out the http://[Host] and leaves only the relative path. * * @param header The initial header, to be modified. * @param oldLength The number of bytes in the header parameter. * @return The length in bytes of the new header. */ void* stripAbsURL(void* header, long int oldLength, long int* newL) { void* newHeader; long int newLength, firstHalf, secondHalf; char* http = "http://"; void* start, *end; char toFind[10000]; char* host = getHeaderField(header, oldLength, "\nHost"); if (!host) { /* this is bad */ #ifdef DEBUG printf("No host found in header!\n"); #endif return NULL; } /* set new header length (+1 for slash) */ newLength = oldLength - strlen(http) - strlen(host); (*newL) = newLength; #ifdef DEBUG printf("Header length changed from %ld to %ld.\n", oldLength, newLength); printf("Host counted: |%s%s|\n", http, host); printf("Host length: %d\n", strlen(http) + strlen(host)); #endif newHeader = calloc(newLength, sizeof(char)); if (!newHeader) { /* crap on a stick */ #ifdef DEBUG printf("Error allocating memory for resized header.\n"); #endif return NULL; } /* create a duplicate of the part of the header we want to replace */ memset(&toFind, 0, sizeof(toFind)); snprintf(toFind, (sizeof(toFind) - 1), "%s%s", http, host); free(host); /* no memory leaks, kthx */ /* position the two pointers at the start and end of the abs URL */ start = strchr((char*)header, ' '); /* first space */ end = ((char*)start) + strlen(toFind) + 1; /* banking on trailing slash */ /* do insanely complicated memory mappings... */ firstHalf = (char*)start - (char*)header + 1; secondHalf = (oldLength - (strlen(toFind))) - firstHalf; memcpy((char*)newHeader, (char*)header, firstHalf); memcpy(((char*)newHeader + ((char*)start - (char*)header + 1)), end, secondHalf); /* first step copies the protocol and the blank space */ /* the second step copies from the first / to the end of the header */ #ifdef DEBUG printf("Test length: %d\n", strlen(toFind)); printf("Old Header: %ld\nNew Header: %ld\n", oldLength, newLength); printf("Pre-bytes copied: %ld\n", firstHalf); printf("Post-bytes copied: %ld\n", secondHalf); #endif /* return the new header */ return newHeader; }