Index: tools/OmahaCompatibility/HttpServer/http_server.cc |
diff --git a/tools/OmahaCompatibility/HttpServer/http_server.cc b/tools/OmahaCompatibility/HttpServer/http_server.cc |
deleted file mode 100644 |
index 0370eac08e5222275aa95d8d2e42d475cc647a6f..0000000000000000000000000000000000000000 |
--- a/tools/OmahaCompatibility/HttpServer/http_server.cc |
+++ /dev/null |
@@ -1,347 +0,0 @@ |
-// Copyright 2008-2009 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
-// ======================================================================== |
- |
- |
-#include "omaha/tools/omahacompatibility/httpserver/http_server.h" |
- |
-#include <Windows.h> |
-#include <http.h> |
-#include <winhttp.h> |
-#include "omaha/common/error.h" |
-#include "omaha/common/debug.h" |
-#include "omaha/common/logging.h" |
-#include "omaha/common/string.h" |
-#include "omaha/common/utils.h" |
-#include "omaha/common/reg_key.h" |
- |
-namespace omaha { |
- |
-#define MAX_BUFFER_SIZE 4048 |
-#define INTERNET_MAX_PATH_LENGTH 2048 |
- |
-HttpServer::HttpServer(const CString& host, int port) |
- : host_(host), |
- port_(port) { |
- CORE_LOG(L1, (_T("[HttpServer]"))); |
- url_prefix_.Format(_T("http://%s:%d"), host, port); |
-} |
- |
-HttpServer::~HttpServer() { |
- CORE_LOG(L1, (_T("[~HttpServer]"))); |
- ::HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); |
- |
- std::map<CString, UrlHandler*>::iterator iter = handlers_.begin(); |
- for (; iter != handlers_.end(); ++iter) { |
- std::pair<CString, UrlHandler*> pair = *iter; |
- VERIFY1(::HttpRemoveUrl(get(request_handle_), |
- pair.first) != NO_ERROR); |
- delete pair.second; |
- } |
- |
- handlers_.clear(); |
-} |
- |
-HRESULT HttpServer::Initialize() { |
- CORE_LOG(L1, (_T("[Initialize]"))); |
- HTTPAPI_VERSION version = HTTPAPI_VERSION_1; |
- int ret = ::HttpInitialize(version, |
- HTTP_INITIALIZE_SERVER, |
- NULL); |
- if (ret != NO_ERROR) { |
- return HRESULT_FROM_WIN32(ret); |
- } |
- |
- ret = ::HttpCreateHttpHandle(address(request_handle_), NULL); |
- if (ret != NO_ERROR) { |
- return HRESULT_FROM_WIN32(ret); |
- } |
- ASSERT1(get(request_handle_)); |
- |
- return S_OK; |
-} |
- |
-HRESULT HttpServer::AddUrlHandler(UrlHandler* handler) { |
- CORE_LOG(L1, (_T("[AddUrlHandler]"))); |
- ASSERT1(handler); |
- |
- CString full_url = url_prefix_ + handler->get_url_path(); |
- int ret = ::HttpAddUrl(get(request_handle_), |
- full_url, NULL); |
- if (ret != NO_ERROR) { |
- return HRESULT_FROM_WIN32(ret); |
- } |
- |
- ASSERT1(handlers_.find(handler->get_url_path()) == handlers_.end()); |
- handlers_[handler->get_url_path()] = handler; |
- return S_OK; |
-} |
- |
-UrlHandler* HttpServer::GetHandler(const HttpRequest& req) { |
- std::map<CString, UrlHandler*>::const_iterator iter = handlers_.begin(); |
- for (; iter != handlers_.end(); ++iter) { |
- UrlHandler* handler = (*iter).second; |
- |
- // Determine if the handler starts with the path that is specified |
- // in the request. |
- if (req.path().Find(handler->get_url_path()) == 0) { |
- return handler; |
- } |
- } |
- |
- ASSERT1(false); |
- return NULL; |
-} |
- |
-HRESULT HttpServer::ReadRequest(HttpRequest* request) { |
- ASSERT1(request); |
- |
- TCHAR buffer[MAX_BUFFER_SIZE] = {0}; |
- HTTP_REQUEST* req = reinterpret_cast<HTTP_REQUEST*>(buffer); |
- int ret = ::HttpReceiveHttpRequest(get(request_handle_), |
- HTTP_NULL_ID, |
- HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, |
- req, |
- MAX_BUFFER_SIZE, |
- NULL, |
- NULL); |
- |
- if (ret != NO_ERROR) { |
- HRESULT hr = HRESULT_FROM_WIN32(ret); |
- CORE_LOG(L1, (_T("[Failed to read request.][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- // Figure out the query string and the path. |
- CString url_path(req->pRawUrl); |
- int idx = url_path.ReverseFind(_T('?')); |
- CString query_str; |
- CString path; |
- if (idx != -1) { |
- query_str = url_path.Right(url_path.GetLength() - idx - 1); |
- path = url_path.Left(idx); |
- } else { |
- path = url_path; |
- } |
- |
- // Set the values on the request. |
- request->set_http_verb(req->Verb); |
- request->set_path(path); |
- request->set_http_request(*req); |
- request->set_query_str(query_str); |
- |
- if (req->Verb == HttpVerbPOST) { |
- DWORD bytes_received = 0; |
- char output_buffer[MAX_BUFFER_SIZE] = {0}; |
- ret = ::HttpReceiveRequestEntityBody(get(request_handle_), |
- req->RequestId, |
- 0, |
- output_buffer, |
- MAX_BUFFER_SIZE, |
- &bytes_received, |
- NULL); |
- |
- if (ret != NO_ERROR) { |
- HRESULT hr = HRESULT_FROM_WIN32(ret); |
- CORE_LOG(L1, (_T("[Failed to read request.][0x%08x]"), hr)); |
- return hr; |
- } |
- CString content = Utf8ToWideChar(output_buffer, bytes_received); |
- request->set_content(content); |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT HttpServer::SetHeader(HTTP_RESPONSE* http_response, |
- HTTP_HEADER_ID header_id, |
- const char* value) { |
- ASSERT1(http_response); |
- |
- http_response->Headers.KnownHeaders[header_id].pRawValue = value; |
- http_response->Headers.KnownHeaders[header_id].RawValueLength = |
- static_cast<USHORT>(strlen(value)); |
- return S_OK; |
-} |
- |
-HRESULT HttpServer::SendResponse(const HttpResponse& response) { |
- const HttpRequest& request = response.request(); |
- const char* const kOk = "OK"; |
- |
- HTTP_RESPONSE http_response = {0}; |
- http_response.StatusCode = 200; |
- |
- // Send back an ok. |
- http_response.pReason = kOk; |
- http_response.ReasonLength = static_cast<USHORT>(strlen(kOk)); |
- |
- // No special headers for now. |
- HTTP_RESPONSE_HEADERS headers = {0}; |
- headers.UnknownHeaderCount = 0; |
- headers.TrailerCount = 0; |
- http_response.Headers = headers; |
- |
- scoped_hfile handle; |
- CStringA request_body_utf8; |
- CStringA content_range_header; |
- int http_response_flag = 0; |
- |
- HTTP_DATA_CHUNK chunk; |
- memset(&chunk, 0, sizeof(HTTP_DATA_CHUNK)); |
- |
- // Based on the verb build a response. |
- if (request.http_verb() == HttpVerbPOST) { |
- // Add a known header of content type. |
- SetHeader(&http_response, HttpHeaderContentType, "text/xml; charset=UTF-8"); |
- |
- // Send back the content. |
- chunk.DataChunkType = HttpDataChunkFromMemory; |
- CString response_str = response.response_str(); |
- request_body_utf8 = CT2A(response_str, CP_UTF8); |
- |
- chunk.FromMemory.pBuffer = request_body_utf8.GetBuffer(); |
- chunk.FromMemory.BufferLength = request_body_utf8.GetLength(); |
- |
- http_response.EntityChunkCount = 1; |
- http_response.pEntityChunks = &chunk; |
- |
- } else if (request.http_verb() == HttpVerbHEAD) { |
- // Add the content length, type, and content range headers. |
- SetHeader(&http_response, HttpHeaderContentType, |
- "application/octet-stream"); |
- char size_str[MAX_PATH] = {0}; |
- _itoa(response.size(), size_str, 10); |
- SetHeader(&http_response, HttpHeaderContentLength, size_str); |
- SetHeader(&http_response, HttpHeaderAcceptRanges, "bytes"); |
- |
- } else if (request.http_verb() == HttpVerbGET) { |
- SetHeader(&http_response, HttpHeaderContentType, |
- "application/octet-stream"); |
- char size_str[MAX_PATH] = {0}; |
- _itoa(response.size(), size_str, 10); |
- SetHeader(&http_response, HttpHeaderAcceptRanges, "bytes"); |
- |
- reset(handle, ::CreateFile(response.file_name(), GENERIC_READ, |
- FILE_SHARE_READ, NULL, OPEN_EXISTING, |
- FILE_ATTRIBUTE_NORMAL, NULL)); |
- if (!handle) { |
- return HRESULTFromLastError(); |
- } |
- |
- chunk.DataChunkType = HttpDataChunkFromFileHandle; |
- |
- // Determine the file portion to send back to the client. |
- // If the client has sent a range request, honor that. |
- int start_file_pos = 0; |
- int end_file_pos = 0; |
- HTTP_REQUEST tmp_request = request.http_request(); |
- if (tmp_request.Headers.KnownHeaders[HttpHeaderRange].RawValueLength != 0) { |
- // The client send a content length header. We need to honor this. |
- CStringA content_range( |
- tmp_request.Headers.KnownHeaders[HttpHeaderRange].pRawValue); |
- |
- int idx = content_range.Find('-'); |
- ASSERT1(idx != -1); |
- end_file_pos = atoi(content_range.Right( |
- content_range.GetLength() - idx - 1)); |
- int st_idx = content_range.Find('='); |
- ASSERT1(st_idx != -1); |
- start_file_pos = atoi(content_range.Mid(st_idx + 1, idx)); |
- |
- // Set the Content-range header in the response. |
- content_range_header.Format("bytes %d-%d/%d", |
- start_file_pos, |
- end_file_pos, response.size()); |
- SetHeader(&http_response, HttpHeaderContentRange, content_range_header); |
- |
- // Since this is a range request, we set the http response code to |
- // partial response. |
- http_response.StatusCode = 206; |
- |
- // Set the value of the human readable text to partial-content. |
- const char* const kPartialContent = "Partial Content"; |
- http_response.pReason = kPartialContent; |
- http_response.ReasonLength = static_cast<USHORT>(strlen(kPartialContent)); |
- } |
- |
- // Send back the entire file or part of it. |
- HTTP_BYTE_RANGE byte_range = {0}; |
- byte_range.StartingOffset.HighPart = 0; |
- byte_range.StartingOffset.LowPart = start_file_pos; |
- if (end_file_pos == 0) { |
- byte_range.Length.QuadPart = HTTP_BYTE_RANGE_TO_EOF; |
- } else { |
- byte_range.Length.QuadPart = end_file_pos - start_file_pos + 1; |
- } |
- |
- chunk.FromFileHandle.ByteRange = byte_range; |
- chunk.FromFileHandle.FileHandle = get(handle); |
- |
- http_response.EntityChunkCount = 1; |
- http_response.pEntityChunks = &chunk; |
- } |
- |
- DWORD bytes_sent = 0; |
- int ret = ::HttpSendHttpResponse( |
- get(request_handle_), |
- request.http_request().RequestId, |
- http_response_flag, |
- &http_response, |
- NULL, |
- &bytes_sent, |
- NULL, |
- 0, |
- NULL, |
- NULL); |
- if (ret != NO_ERROR) { |
- return HRESULT_FROM_WIN32(ret); |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT HttpServer::Start() { |
- CORE_LOG(L1, (_T("[Start]"))); |
- |
- while (true) { |
- HttpRequest request; |
- HRESULT hr = ReadRequest(&request); |
- if (FAILED(hr)) { |
- CORE_LOG(L1, (_T("[ReadRequest failed.][0x%08x]"), hr)); |
- continue; |
- } |
- |
- HttpResponse response(request); |
- UrlHandler* handler = GetHandler(request); |
- if (handler == NULL) { |
- continue; |
- } |
- |
- hr = handler->HandleRequest(request, &response); |
- if (FAILED(hr)) { |
- CORE_LOG(L1, (_T("[HandlerRequest failed.][0x%08x]"), hr)); |
- continue; |
- } |
- |
- hr = SendResponse(response); |
- if (FAILED(hr)) { |
- CORE_LOG(L1, (_T("[SendRequest failed.][0x%08x]"), hr)); |
- continue; |
- } |
- } |
- |
- return S_OK; |
-} |
- |
-} // namespace omaha |