/* Read non-header data from connection */ static EIO_Status s_Read(SHttpConnector* uuu, void* buf, size_t size, size_t* n_read) { EIO_Status status; assert(uuu->sock); if (uuu->flags & fHCC_UrlDecodeInput) { /* read and URL-decode */ size_t n_peeked, n_decoded; size_t peek_size = 3 * size; void* peek_buf = malloc(peek_size); /* peek the data */ status= SOCK_Read(uuu->sock,peek_buf,peek_size,&n_peeked,eIO_ReadPeek); if (status != eIO_Success) { assert(!n_peeked); *n_read = 0; } else { if (URL_Decode(peek_buf,n_peeked,&n_decoded,buf,size,n_read)) { /* decode, then discard successfully decoded data from input */ if (n_decoded) { SOCK_Read(uuu->sock,0,n_decoded,&n_peeked,eIO_ReadPersist); assert(n_peeked == n_decoded); uuu->received += n_decoded; status = eIO_Success; } else if (SOCK_Status(uuu->sock, eIO_Read) == eIO_Closed) { /* we are at EOF, and remaining data cannot be decoded */ status = eIO_Unknown; } } else status = eIO_Unknown; if (status != eIO_Success) CORE_LOG_X(16, eLOG_Error, "[HTTP] Cannot URL-decode data"); } free(peek_buf); } else { /* just read, with no URL-decoding */ status = SOCK_Read(uuu->sock, buf, size, n_read, eIO_ReadPlain); uuu->received += *n_read; } if (uuu->expected) { if (uuu->received > uuu->expected) return eIO_Unknown/*received too much*/; if (uuu->expected != (size_t)(-1L)) { if (status == eIO_Closed && uuu->expected > uuu->received) return eIO_Unknown/*received too little*/; } else if (uuu->received) return eIO_Unknown/*received too much*/; } return status; }
static void TEST_URL_Encoding(void) { typedef struct { const char* src_buf; size_t src_size; size_t src_read; const char* dst_buf; size_t dst_size; size_t dst_written; int/*bool*/ ok; } STestArg; static const STestArg s_TestEncode[] = { { "", 0, 0, "", 0, 0, 1/*true*/ }, { "abc", 3, 3, "abc", 3, 3, 1/*true*/ }, { "_ _%_;_\n_", 7, 0, "", 0, 0, 1/*true*/ }, { "_ _%_;_\n_", 0, 0, "", 0, 0, 1/*true*/ }, { "_ _%_;_\n_", 0, 0, "", 7, 0, 1/*true*/ }, { "_ _%_;_\n_:_\\_\"_", 15, 15, "_+_%25_%3B_%0A_%3A_%5C_%22_", 27, 27, 1/*true*/ }, { "_ _%_;_\n_:_\\_\"_", 15, 13, "_+_%25_%3B_%0A_%3A_%5C_%22_", 25, 23, 1/*true*/ }, { "_%_", 3, 1, "_%25_", 2, 1, 1/*true*/ }, { "_ _%_;_\n_", 7, 7, "_+_%25_%3B_%0A", 100, 11, 1/*true*/ } }; static const STestArg s_TestDecode[] = { { "", 0, 0, "", 0, 0, 1/*true*/ }, { "%25", 1, 0, "", 0, 0, 1/*true*/ }, { "%25", 2, 0, "", 0, 0, 1/*true*/ }, { "%25", 3, 3, "%", 1, 1, 1/*true*/ }, { "%25", 3, 0, "%", 0, 0, 1/*true*/ }, { "%%%", 2, 0, "", 1, 0, 0/*false*/ }, { "%%%", 3, 0, "", 1, 0, 0/*false*/ }, { "%xy", 3, 0, "", 1, 0, 0/*false*/ }, { "\n", 1, 0, "", 1, 0, 0/*false*/ }, { "a\t", 2, 1, "a", 1, 1, 1/*true*/ }, { "#\n", 1, 0, "", 0, 0, 1/*true*/ }, { "%a-", 3, 0, "", 1, 0, 0/*false*/ }, { "%a-", 3, 0, "", 0, 0, 1/*true*/ }, { "_+_%25_%3B_%0A_%3A_%5C_%22_", 27, 27, "_ _%_;_\n_:_\\_\"_", 15, 15, 1/*true*/ }, { "_+_%25_%3B_%0A_%3A_%5C_%22_", 25, 23, "_ _%_;_\n_:_\\_\"_", 13, 13, 1/*true*/ }, { "_+_%25_%3B_%0A_%3A_%5C_%22_", 27, 23, "_ _%_;_\n_:_\\_\"_", 13, 13, 1/*true*/ } }; static const STestArg s_TestDecodeEx[] = { { "", 0, 0, "", 0, 0, 1/*true*/ }, { "%25", 3, 0, "%", 0, 0, 1/*true*/ }, { "%%%", 2, 0, "", 1, 0, 0/*false*/ }, { "%xy", 3, 0, "", 1, 0, 0/*false*/ }, { "\n", 1, 0, "", 1, 0, 0/*false*/ }, { ">>a", 3, 3, ">>a", 3, 3, 1/*true*/ }, { ">b[", 3, 3, ">b[", 4, 3, 1/*true*/ }, { ">b]", 3, 2, ">b", 3, 2, 1/*true*/ }, { "[b]", 3, 2, "[b", 3, 2, 1/*true*/ }, { "<b>", 3, 0, "", 3, 0, 0/*false*/ }, { "<e>", 3, 0, "", 5, 0, 0/*false*/ } }; size_t i; size_t src_read, dst_written; char dst[1024]; #define ARRAY_DIM(arr) (sizeof(arr)/sizeof((arr)[0])) CORE_LOG(eLOG_Note, "URL encoding test started"); for (i = 0; i < ARRAY_DIM(s_TestEncode); i++) { const STestArg* arg = &s_TestEncode[i]; URL_Encode(arg->src_buf, arg->src_size, &src_read, dst, arg->dst_size, &dst_written); assert(src_read == arg->src_read); assert(dst_written == arg->dst_written); assert(!dst_written || !memcmp(dst, arg->dst_buf, dst_written)); } for (i = 0; i < ARRAY_DIM(s_TestDecode); i++) { const STestArg* arg = &s_TestDecode[i]; int/*bool*/ ok = URL_Decode(arg->src_buf, arg->src_size, &src_read, dst, arg->dst_size, &dst_written); assert(ok == arg->ok); assert(src_read == arg->src_read); assert(dst_written == arg->dst_written); assert(!dst_written || !memcmp(dst, arg->dst_buf, dst_written)); } for (i = 0; i < ARRAY_DIM(s_TestDecodeEx); i++) { const STestArg* arg = &s_TestDecodeEx[i]; int/*bool*/ ok = URL_DecodeEx(arg->src_buf, arg->src_size, &src_read, dst, arg->dst_size, &dst_written, "[>"); assert(ok == arg->ok); assert(src_read == arg->src_read); assert(dst_written == arg->dst_written); assert(!dst_written || !memcmp(dst, arg->dst_buf, dst_written)); } CORE_LOG(eLOG_Note, "URL encoding test completed"); }