static void getBody(xmlrpc_env * const envP, TSession * const abyssSessionP, size_t const contentSize, const char * const trace, xmlrpc_mem_block ** const bodyP) { /*---------------------------------------------------------------------------- Get the entire body, which is of size 'contentSize' bytes, from the Abyss session and return it as the new memblock *bodyP. The first chunk of the body may already be in Abyss's buffer. We retrieve that before reading more. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * body; if (trace) fprintf(stderr, "XML-RPC handler processing body. " "Content Size = %u bytes\n", (unsigned)contentSize); body = xmlrpc_mem_block_new(envP, 0); if (!envP->fault_occurred) { size_t bytesRead; const char * chunkPtr; size_t chunkLen; bytesRead = 0; while (!envP->fault_occurred && bytesRead < contentSize) { SessionGetReadData(abyssSessionP, contentSize - bytesRead, &chunkPtr, &chunkLen); bytesRead += chunkLen; assert(bytesRead <= contentSize); XMLRPC_MEMBLOCK_APPEND(char, envP, body, chunkPtr, chunkLen); if (bytesRead < contentSize) refillBufferFromConnection(envP, abyssSessionP, trace); } if (envP->fault_occurred) xmlrpc_mem_block_free(body); else *bodyP = body; } }
static xmlrpc_mem_block * serialize_fault (int fault_code, const char *fault_string) { xmlrpc_env tmp_env; xmlrpc_env fault; xmlrpc_mem_block *output; xmlrpc_env_init (&tmp_env); xmlrpc_env_init (&fault); output = xmlrpc_mem_block_new (&tmp_env, 0); XMLRPC_FAIL_IF_FAULT (&tmp_env); xmlrpc_env_set_fault (&fault, fault_code, (char *) fault_string); xmlrpc_serialize_fault (&tmp_env, output, &fault); XMLRPC_FAIL_IF_FAULT (&tmp_env); return output; cleanup: return NULL; } /* serialize_fault */
/* * 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); }
static void test_mem_block (void) { xmlrpc_env env; xmlrpc_mem_block* block; xmlrpc_mem_block* typed_heap_block; xmlrpc_mem_block typed_auto_block; void** typed_contents; xmlrpc_env_init(&env); /* Allocate a zero-size block. */ block = xmlrpc_mem_block_new(&env, 0); TEST_NO_FAULT(&env); TEST(block != NULL); TEST(xmlrpc_mem_block_size(block) == 0); /* Grow the block a little bit. */ xmlrpc_mem_block_resize(&env, block, strlen(test_string_1) + 1); TEST_NO_FAULT(&env); TEST(xmlrpc_mem_block_size(block) == strlen(test_string_1) + 1); /* Insert a string into the block, and resize it by large amount. ** We want to cause a reallocation and copy of the block contents. */ strcpy(xmlrpc_mem_block_contents(block), test_string_1); xmlrpc_mem_block_resize(&env, block, 10000); TEST_NO_FAULT(&env); TEST(xmlrpc_mem_block_size(block) == 10000); TEST(strcmp(xmlrpc_mem_block_contents(block), test_string_1) == 0); /* Test cleanup code (with help from memprof). */ xmlrpc_mem_block_free(block); /* Allocate a bigger block. */ block = xmlrpc_mem_block_new(&env, 128); TEST_NO_FAULT(&env); TEST(block != NULL); TEST(xmlrpc_mem_block_size(block) == 128); /* Test cleanup code (with help from memprof). */ xmlrpc_mem_block_free(block); /* Allocate a "typed" memory block. */ typed_heap_block = XMLRPC_TYPED_MEM_BLOCK_NEW(void*, &env, 20); TEST_NO_FAULT(&env); TEST(typed_heap_block != NULL); TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 20); typed_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(void*, typed_heap_block); TEST(typed_contents != NULL); /* Resize a typed memory block. */ XMLRPC_TYPED_MEM_BLOCK_RESIZE(void*, &env, typed_heap_block, 100); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 100); /* Test cleanup code (with help from memprof). */ XMLRPC_TYPED_MEM_BLOCK_FREE(void*, typed_heap_block); /* Test _INIT and _CLEAN for stack-based memory blocks. */ XMLRPC_TYPED_MEM_BLOCK_INIT(void*, &env, &typed_auto_block, 30); TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, &typed_auto_block) == 30); XMLRPC_TYPED_MEM_BLOCK_CLEAN(void*, &typed_auto_block); /* Test xmlrpc_mem_block_append. */ block = XMLRPC_TYPED_MEM_BLOCK_NEW(int, &env, 5); TEST_NO_FAULT(&env); memcpy(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block), test_int_array_1, sizeof(test_int_array_1)); XMLRPC_TYPED_MEM_BLOCK_APPEND(int, &env, block, test_int_array_2, 3); TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(int, block) == 8); TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block), test_int_array_3, sizeof(test_int_array_3)) == 0); XMLRPC_TYPED_MEM_BLOCK_FREE(int, block); xmlrpc_env_clean(&env); }