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;
	}
}
Beispiel #2
0
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;
}