Beispiel #1
0
bool kul::http::Server::get(PHTTP_REQUEST req){
	HTTP_RESPONSE response;
	initialiseReponse(response, 200, "OK");
	addKnownHeader(response, HttpHeaderContentType, "text/html");

	HTTP_DATA_CHUNK dataChunk;
	DWORD		   result;
	DWORD		   bytesSent;

	std::string s(req->pRawUrl);
	std::string a;
	if(s.find("?") != std::string::npos){
		a = s.substr(s.find("?") + 1);
		s = s.substr(0, s.find("?"));
	}
	const std::pair<kul::hash::set::String, std::string>& p(handle(s, asAttributes(a)));
	if(p.second.size()){
		dataChunk.DataChunkType 			= HttpDataChunkFromMemory;
		dataChunk.FromMemory.pBuffer 		= (PVOID) p.second.c_str();
		dataChunk.FromMemory.BufferLength 	= p.second.size();

		response.EntityChunkCount 			= 1;
		response.pEntityChunks 				= &dataChunk;
	}
	result = HttpSendHttpResponse(this->q, req->RequestId, 0, &response, NULL, &bytesSent, NULL, 0, NULL, NULL); 
	if(result != NO_ERROR)
		KEXCEPT(Exception, "HttpSendHttpResponse failed with: " + std::to_string(result));

	return result;
}
/*
 * SendHttpResponse sends a text/html content type back with
 * the user specified status code and reason.  Used for returning
 * errors to clients.
 */
DWORD
SendHttpResponse(
    IN HANDLE        hReqQueue,
    IN PHTTP_REQUEST pRequest,
    IN USHORT        StatusCode,
    IN PSTR          pReason,
    IN PSTR          pEntityString
    )
{
    HTTP_RESPONSE   response;
    HTTP_DATA_CHUNK dataChunk;
    DWORD           result;
    DWORD           bytesSent;
    CHAR            szServerHeader[20];

    // Initialize the HTTP response structure.
    INITIALIZE_HTTP_RESPONSE(&response, StatusCode, pReason);

    ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/html");
    
    StringCchPrintfA(szServerHeader, sizeof(szServerHeader), "Xmlrpc-c/%s",
                     XMLRPC_C_VERSION);
    ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader);
   
    if(pEntityString)
    {
        // Add an entity chunk
        dataChunk.DataChunkType           = HttpDataChunkFromMemory;
        dataChunk.FromMemory.pBuffer      = pEntityString;
        dataChunk.FromMemory.BufferLength = (ULONG) strlen(pEntityString);

        response.EntityChunkCount         = 1;
        response.pEntityChunks            = &dataChunk;
    }

    // Since we are sending all the entity body in one call, we don't have 
    // to specify the Content-Length.
    result = HttpSendHttpResponse(
        hReqQueue,           // ReqQueueHandle
        pRequest->RequestId, // Request ID
        0,                   // Flags
        &response,           // HTTP response
        NULL,                // pReserved1
        &bytesSent,          // bytes sent   (OPTIONAL)
        NULL,                // pReserved2   (must be NULL)
        0,                   // Reserved3    (must be 0)
        NULL,                // LPOVERLAPPED (OPTIONAL)
        NULL                 // pReserved4   (must be NULL)
        );

    if(result != NO_ERROR)
    {
        TraceW(L"HttpSendHttpResponse failed with %lu", result);
    }

    return result;
}
DWORD
SendHttpResponseAuthRequired(
    IN HANDLE        hReqQueue,
    IN PHTTP_REQUEST pRequest
    )
{
    HTTP_RESPONSE   response;
    DWORD           result;
    DWORD           bytesSent;
    CHAR            szServerHeader[20];

    // Initialize the HTTP response structure.
    INITIALIZE_HTTP_RESPONSE(&response, 401, "Authentication Required");

    // Add the WWW_Authenticate header.
    ADD_KNOWN_HEADER(response, HttpHeaderWwwAuthenticate,
                     "Basic realm=\"xmlrpc\"");
    
    StringCchPrintfA(szServerHeader, sizeof(szServerHeader), "Xmlrpc-c/%s",
                     XMLRPC_C_VERSION);
    ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader);
   
    // Since we are sending all the entity body in one call, we don't have 
    // to specify the Content-Length.
    result = HttpSendHttpResponse(
        hReqQueue,           // ReqQueueHandle
        pRequest->RequestId, // Request ID
        0,                   // Flags
        &response,           // HTTP response
        NULL,                // pReserved1
        &bytesSent,          // bytes sent   (OPTIONAL)
        NULL,                // pReserved2   (must be NULL)
        0,                   // Reserved3    (must be 0)
        NULL,                // LPOVERLAPPED (OPTIONAL)
        NULL                 // pReserved4   (must be NULL)
        );

    if(result != NO_ERROR)
    {
        TraceW(L"SendHttpResponseAuthRequired failed with %lu", result);
    }

    return result;
}
Beispiel #4
0
DWORD
SendHttpResponse(    
    IN PHTTP_REQUEST	pRequest,
	IN PHTTP_IO_CONTEXT pContext,
    IN USHORT			StatusCode,
    IN PSTR				pReason,
    IN PSTR				pEntityString,
	IN PSTR				pContentLength
    )
{    
    HTTP_DATA_CHUNK dataChunk;
    DWORD           result;
	PHTTP_LISTENER listener = pContext->listener;
	PHTTP_IO_CONTEXT pResponseContext = GetIOContext();

	//
    // Initialize the HTTP response structure.
    //	
    pResponseContext->Reponse.StatusCode = (StatusCode);     
	pResponseContext->Reponse.pReason = (pReason);        
    pResponseContext->Reponse.ReasonLength = (USHORT) strlen(pReason);  

    //
    // Add a known header.
    //
    //ADD_KNOWN_HEADER
	pResponseContext->Reponse.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = "text/html"; 
	pResponseContext->Reponse.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen("text/html");

	DEBUG_ASSERT(pEntityString);

	dataChunk.DataChunkType						= HttpDataChunkFromMemory;
    dataChunk.FromMemory.pBuffer				= pEntityString;
    dataChunk.FromMemory.BufferLength			= (ULONG) strlen(pEntityString);
    pResponseContext->Reponse.EntityChunkCount  = 1;
    pResponseContext->Reponse.pEntityChunks		= &dataChunk;		
		   
    // 
    // Since we are sending all the entity body in one call, we don't have 
    // to specify the Content-Length.
    //	
	pResponseContext->operationState = HTTP_LISTENER_STATE_RESPONSE;
	
	// Enqueue async IO Request.
	StartThreadpoolIo(listener->pthreadPoolIO);
    result = HttpSendHttpResponse(
                    listener->hRequestQueue,		// ReqQueueHandle
                    pRequest->RequestId,			// Request ID
                    0,								// Flags
                    &pResponseContext->Reponse,		// HTTP response
                    NULL,							// cache policy
                    NULL,							// bytes sent   (OPTIONAL)
                    NULL,							// pReserved2   (must be NULL)
                    0,								// Reserved3    (must be 0)
                    pResponseContext,				// LPOVERLAPPED (OPTIONAL)
                    NULL							// pReserved4   (must be NULL)
                    );

	if(result != NO_ERROR && result != ERROR_IO_PENDING)
	{
		// need to call this whenever an async I/O operation fails synchronously
		CancelThreadpoolIo(listener->pthreadPoolIO); 
		LOG_ERROR(L"\nSynchronous completion response processing error - %lu", result);
		return result;
	}
	else if(result == NO_ERROR)
	{		
		// Synchronous completion		
		CancelThreadpoolIo(listener->pthreadPoolIO);
		HttpInputQueueEnqueue(listener, 
							  pResponseContext);
	}
	else
	{	
		DEBUG_ASSERT(result == ERROR_IO_PENDING)	
	}

    return NO_ERROR;
}
/*
 * processRPCCall() is called after some validations.  The assumption is that
 * the request is an HTTP post of content-type text/xml with a content-length
 * that is less than the maximum the library can handle.
 *
 * The caller should check the error status, and if the error was other than
 * a network type, respond back to the client to let them know the call failed.
 */
void
processRPCCall(
    xmlrpc_env *     const envP,
    IN HANDLE        hReqQueue,
    IN PHTTP_REQUEST pRequest
    )
{
    HTTP_RESPONSE   response;
    DWORD           result;
    DWORD           bytesSent;
    PUCHAR          pEntityBuffer;
    ULONG           EntityBufferLength;
    ULONG           BytesRead;
#define MAX_ULONG_STR ((ULONG) sizeof("4294967295"))
    CHAR            szContentLength[MAX_ULONG_STR];
    CHAR            szServerHeader[20];
    HTTP_DATA_CHUNK dataChunk;
    ULONG           TotalBytesRead = 0;
    xmlrpc_mem_block * body;
    xmlrpc_mem_block * output;

    BytesRead  = 0;
    body       = NULL;
    output     = NULL;

    // Allocate some space for an entity buffer.
    EntityBufferLength = 2048;  
    pEntityBuffer      = (PUCHAR) ALLOC_MEM( EntityBufferLength );
    if (pEntityBuffer == NULL)
    {
        xmlrpc_faultf(envP, "Out of Memory");
        goto Done;
    }

    // NOTE: If we had passed the HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY
    //       flag with HttpReceiveHttpRequest(), the entity would have
    //       been a part of HTTP_REQUEST (using the pEntityChunks field).
    //       Since we have not passed that flag, we can be assured that 
    //       there are no entity bodies in HTTP_REQUEST.
    if(pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS)
    {
        //Allocate some space for an XMLRPC memory block.
        body = xmlrpc_mem_block_new(envP, 0);
        if (envP->fault_occurred) 
            goto Done;

        // The entity body can be sent over multiple calls. Let's collect all
        // of these in a buffer and send the buffer to the xmlrpc-c library 
        do
        {
            // Read the entity chunk from the request.
            BytesRead = 0; 
            result = HttpReceiveRequestEntityBody(
                hReqQueue,
                pRequest->RequestId,
                0,
                pEntityBuffer,
                EntityBufferLength,
                &BytesRead,
                NULL
                );
            switch(result)
            {
                case NO_ERROR:
                    if(BytesRead != 0)
                    {
                        XMLRPC_MEMBLOCK_APPEND(char, envP, body, 
                                               pEntityBuffer, BytesRead);
                        if(envP->fault_occurred)
                            goto Done;                      
                    }
                    break;

                case ERROR_HANDLE_EOF:
                    // We have read the last request entity body. We can now 
                    // process the suppossed XMLRPC data.
                    if(BytesRead != 0)
                    {
                        XMLRPC_MEMBLOCK_APPEND(char, envP, body, 
                                               pEntityBuffer, BytesRead);
                        if(envP->fault_occurred)
                            goto Done;
                    }

                    // We will send the response over multiple calls. 
                    // This is achieved by passing the 
                    // HTTP_SEND_RESPONSE_FLAG_MORE_DATA flag.
                    
                    // NOTE: Since we are accumulating the TotalBytesRead in 
                    //       a ULONG, this will not work for entity bodies that
                    //       are larger than 4 GB. To work with large entity
                    //       bodies, we would have to use a ULONGLONG.
                    TraceA("xmlrpc_server RPC2 handler processing "
                           "RPC request.");
                                        
                    // Process the RPC.
                    xmlrpc_registry_process_call2(
                        envP, global_registryP,
                        XMLRPC_MEMBLOCK_CONTENTS(char, body),
                        XMLRPC_MEMBLOCK_SIZE(char, body),
                        NULL,
                        &output);
                    if (envP->fault_occurred) 
                        goto Done;

                    // Initialize the HTTP response structure.
                    INITIALIZE_HTTP_RESPONSE(&response, 200, "OK");

                    //Add the content-length
                    StringCchPrintfA(szContentLength,MAX_ULONG_STR, "%lu",
                                     XMLRPC_MEMBLOCK_SIZE(char, output));
                    ADD_KNOWN_HEADER(
                            response, 
                            HttpHeaderContentLength, 
                            szContentLength );

                    //Add the content-type
                    ADD_KNOWN_HEADER(response, HttpHeaderContentType,
                                     "text/xml");
                    
                    StringCchPrintfA(szServerHeader,20,
                                     "xmlrpc-c %s",XMLRPC_C_VERSION);
                    ADD_KNOWN_HEADER(response, HttpHeaderServer,
                                     szServerHeader);

                    //send the response
                    result = HttpSendHttpResponse(
                        hReqQueue,           // ReqQueueHandle
                        pRequest->RequestId, // Request ID
                        HTTP_SEND_RESPONSE_FLAG_MORE_DATA,
                        &response,           // HTTP response
                        NULL,                // pReserved1
                        &bytesSent,          // bytes sent (optional)
                        NULL,                // pReserved2
                        0,                   // Reserved3
                        NULL,                // LPOVERLAPPED
                        NULL                 // pReserved4
                        );
                    if(result != NO_ERROR)
                    {
                        TraceW(L"HttpSendHttpResponse failed with %lu",
                               result);
                        xmlrpc_env_set_fault_formatted(
                            envP, XMLRPC_NETWORK_ERROR,
                            "HttpSendHttpResponse failed with %lu", result);
                        goto Done;
                    }

                    // Send entity body from a memory chunk.
                    dataChunk.DataChunkType = HttpDataChunkFromMemory;
                    dataChunk.FromMemory.BufferLength =
                        (ULONG)XMLRPC_MEMBLOCK_SIZE(char, output);
                    dataChunk.FromMemory.pBuffer =
                        XMLRPC_MEMBLOCK_CONTENTS(char, output);

                    result = HttpSendResponseEntityBody(
                        hReqQueue,
                        pRequest->RequestId,
                        0,                    // This is the last send.
                        1,                    // Entity Chunk Count.
                        &dataChunk,
                        NULL,
                        NULL,
                        0,
                        NULL,
                        NULL
                        );
                    if(result != NO_ERROR)
                    {
                        TraceW(L"HttpSendResponseEntityBody failed "
                               L"with %lu", result);
                        xmlrpc_env_set_fault_formatted(
                                envP, XMLRPC_NETWORK_ERROR,
                                "HttpSendResponseEntityBody failed with %lu",
                                result);
                        goto Done;
                    }
                    goto Done;
                    break;
                default:
                    TraceW(L"HttpReceiveRequestEntityBody failed with %lu",
                           result);
                    xmlrpc_env_set_fault_formatted(
                                envP, XMLRPC_NETWORK_ERROR,
                                "HttpReceiveRequestEntityBody failed "
                                "with %lu", result);
                    goto Done;
            }
        } while(TRUE);
    }
Beispiel #6
0
bool kul::http::Server::post(PHTTP_REQUEST req){
	HTTP_RESPONSE 	response;
	DWORD 			result;
	DWORD 			bytesSent;
	ULONG 			EntityBufferLength = 512;
	PUCHAR 			rstr = (PUCHAR) wAlloc(EntityBufferLength);
	ULONG 			bytes = 0;
	CHAR 			szContentLength[MAX_ULONG_STR];
	HTTP_DATA_CHUNK dataChunk;

	if (rstr == NULL){
		postClean(rstr);
		KEXCEPT(Exception, "Insufficient resources " + std::to_string(ERROR_NOT_ENOUGH_MEMORY));
	}

	initialiseReponse(response, 200, "OK");
	if(req->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS){
		std::string atts;
		do{
			bytes = 0;
			result = HttpReceiveRequestEntityBody(this->q, req->RequestId, 0, rstr, EntityBufferLength, &bytes, NULL);
			switch(result){
				case NO_ERROR:
					for(ULONG i = 0; i < bytes; i++) atts += rstr[i];
					break;
				case ERROR_HANDLE_EOF:
				{
					for(ULONG i = 0; i < bytes; i++) atts += rstr[i];
					sprintf_s(szContentLength, MAX_ULONG_STR, "%lu", bytes);
					addKnownHeader(response, HttpHeaderContentLength, szContentLength);
					result = HttpSendHttpResponse(this->q, req->RequestId,
								HTTP_SEND_RESPONSE_FLAG_MORE_DATA, &response,
								NULL, &bytesSent, NULL, 0, NULL, NULL);
					if(result != NO_ERROR){
						postClean(rstr);
						KEXCEPT(Exception, "HttpSendHttpResponse failed with: " + std::to_string(result));
					}
					const std::pair<kul::hash::set::String, std::string>& p(handle(req->pRawUrl, asAttributes(atts)));
					dataChunk.DataChunkType 			= HttpDataChunkFromMemory;
					dataChunk.FromMemory.pBuffer 		= (PVOID) p.second.c_str();
					dataChunk.FromMemory.BufferLength 	= p.second.size();
					result = HttpSendResponseEntityBody(this->q, req->RequestId, 0, 1, &dataChunk, NULL, NULL, 0, NULL, NULL);
					if(result != NO_ERROR){
						postClean(rstr);
						KEXCEPT(Exception, "HttpSendResponseEntityBody failed with: " + std::to_string(result));
					}
					break;
				}
				default:
					postClean(rstr);
					return result;
			}
		}while(TRUE);
	}else{ // This request does not have an entity body.
		result = HttpSendHttpResponse(this->q, req->RequestId, 0, &response, NULL, &bytesSent, NULL,0, NULL, NULL);
		if(result != NO_ERROR){
			postClean(rstr);
			KEXCEPT(Exception, "HttpSendHttpResponse failed with: " + std::to_string(result));
		}
	}
	postClean(rstr);
	return result;
}