spectrum2/3rdparty/cpprestsdk/include/cpprest/details/http_server_httpsys.h
2015-11-19 15:19:14 +01:00

250 lines
7.8 KiB
C++

/***
* ==++==
*
* Copyright (c) Microsoft Corporation. All rights reserved.
* 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.
*
* ==--==
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: implementation of HTTP server API built on Windows HTTP Server APIs.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
#error "Error: http server APIs are not supported in XP"
#endif //_WIN32_WINNT < _WIN32_WINNT_VISTA
// Windows Sockets are not code analysis clean.
#pragma warning(push)
#pragma warning(disable : 6386)
#include <http.h>
#pragma warning(pop)
#include <atomic>
#include <mutex>
#include "cpprest/details/http_server.h"
namespace web
{
namespace http
{
namespace experimental
{
namespace details
{
class http_windows_server;
struct windows_request_context;
/// <summary>
/// Class used to wrap OVERLAPPED I/O with any HTTP I/O.
/// </summary>
class http_overlapped : public OVERLAPPED
{
public:
void set_http_io_completion(std::function<void(DWORD, DWORD)> http_io_completion)
{
ZeroMemory(this, sizeof(OVERLAPPED));
m_http_io_completion = http_io_completion;
}
/// <summary>
/// Callback for all I/O completions.
/// </summary>
static void CALLBACK io_completion_callback(
PTP_CALLBACK_INSTANCE instance,
PVOID context,
PVOID pOverlapped,
ULONG result,
ULONG_PTR numberOfBytesTransferred,
PTP_IO io)
{
CASABLANCA_UNREFERENCED_PARAMETER(io);
CASABLANCA_UNREFERENCED_PARAMETER(context);
CASABLANCA_UNREFERENCED_PARAMETER(instance);
http_overlapped *p_http_overlapped = (http_overlapped *)pOverlapped;
p_http_overlapped->m_http_io_completion(result, (DWORD) numberOfBytesTransferred);
}
private:
std::function<void(DWORD, DWORD)> m_http_io_completion;
};
/// <summary>
/// Context for http request through Windows HTTP Server API.
/// </summary>
struct windows_request_context : http::details::_http_server_context
{
windows_request_context();
virtual ~windows_request_context();
// Asynchronously starts processing the current request.
void async_process_request(HTTP_REQUEST_ID request_id, http::http_request msg, const unsigned long headers_size);
// Dispatch request to the provided http_listener.
void dispatch_request_to_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener);
// Read in a portion of the request body.
void read_request_body_chunk();
// Start processing the response.
void async_process_response();
void transmit_body();
// Read request headers io completion callback function .
void read_headers_io_completion(DWORD error_code, DWORD bytes_read);
// Read request body io completion callback function.
void read_body_io_completion(DWORD error_code, DWORD bytes_read);
// Send response io completion callback function .
void send_response_io_completion(DWORD error_code, DWORD bytes_read);
// Send response body io completion callback function.
void send_response_body_io_completion(DWORD error_code, DWORD bytes_read);
// Cancel request io completion callback function.
void cancel_request_io_completion(DWORD error_code, DWORD bytes_read);
// TCE that indicates the completion of response
// Workaround for ppl task_completion_event bug.
std::mutex m_responseCompletedLock;
pplx::task_completion_event<void> m_response_completed;
// Id of the currently processed request on this connection.
HTTP_REQUEST_ID m_request_id;
bool m_sending_in_chunks;
bool m_transfer_encoding;
size_t m_remaining_to_write;
HTTP_REQUEST *m_request;
std::unique_ptr<unsigned char[]> m_request_buffer;
std::unique_ptr<HTTP_UNKNOWN_HEADER []> m_headers;
std::vector<std::string> m_headers_buffer;
http_overlapped m_overlapped;
http_request m_msg;
http_response m_response;
std::exception_ptr m_except_ptr;
private:
windows_request_context(const windows_request_context &);
windows_request_context& operator=(const windows_request_context &);
// Sends entity body chunk.
void send_entity_body(_In_reads_(data_length) unsigned char * data, _In_ size_t data_length);
// Cancels this request.
void cancel_request(std::exception_ptr except_ptr);
std::vector<unsigned char> m_body_data;
};
/// <summary>
/// Class to implement HTTP server API on Windows.
/// </summary>
class http_windows_server : public http_server
{
public:
/// <summary>
/// Constructs a http_windows_server.
/// </summary>
http_windows_server();
/// <summary>
/// Releases resources held.
/// </summary>
~http_windows_server();
/// <summary>
/// Start listening for incoming requests.
/// </summary>
virtual pplx::task<void> start();
/// <summary>
/// Registers an http listener.
/// </summary>
virtual pplx::task<void> register_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener);
/// <summary>
/// Unregisters an http listener.
/// </summary>
virtual pplx::task<void> unregister_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener);
/// <summary>
/// Stop processing and listening for incoming requests.
/// </summary>
virtual pplx::task<void> stop();
/// <summary>
/// Asynchronously sends the specified http response.
/// </summary>
/// <param name="response">The http_response to send.</param>
/// <returns>A operation which is completed once the response has been sent.</returns>
virtual pplx::task<void> respond(http::http_response response);
private:
friend struct details::windows_request_context;
// Structure to hold each registered listener.
class listener_registration
{
public:
listener_registration(HTTP_URL_GROUP_ID urlGroupId)
: m_urlGroupId(urlGroupId)
{}
// URL group id for this listener. Each listener needs it own URL group
// because configuration like timeouts, authentication, etc...
HTTP_URL_GROUP_ID m_urlGroupId;
// Request handler lock to guard against removing a listener while in user code.
pplx::extensibility::reader_writer_lock_t m_requestHandlerLock;
};
// Registered listeners
pplx::extensibility::reader_writer_lock_t _M_listenersLock;
std::unordered_map<web::http::experimental::listener::details::http_listener_impl *, std::unique_ptr<listener_registration>> _M_registeredListeners;
// HTTP Server API server session id.
HTTP_SERVER_SESSION_ID m_serverSessionId;
// Tracks the number of outstanding requests being processed.
std::atomic<int> m_numOutstandingRequests;
pplx::extensibility::event_t m_zeroOutstandingRequests;
// Handle to HTTP Server API request queue.
HANDLE m_hRequestQueue;
// Threadpool I/O structure for overlapped I/O.
TP_IO * m_threadpool_io;
// Task which actually handles receiving requests from HTTP Server API request queue.
pplx::task<void> m_receivingTask;
void receive_requests();
};
} // namespace details;
} // namespace experimental
}} // namespace web::http