Http client: Use better error codes, fix Host headers for webservers not running on port 80, use as the http backend for 3DS/PSP consoles

This commit is contained in:
UnknownShadow200 2023-05-26 18:48:14 +10:00
parent 6cd0dae2a8
commit 42c3b6acfc
4 changed files with 37 additions and 28 deletions

View File

@ -241,13 +241,13 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_MINFILES #define CC_BUILD_MINFILES
#undef CC_BUILD_FREETYPE #undef CC_BUILD_FREETYPE
#elif defined __psp__ #elif defined __psp__
#define CC_BUILD_CURL #define CC_BUILD_HTTPCLIENT
#define CC_BUILD_OPENAL #define CC_BUILD_OPENAL
#define CC_BUILD_PSP #define CC_BUILD_PSP
#undef CC_BUILD_FREETYPE #undef CC_BUILD_FREETYPE
#undef EXTENDED_BLOCKS #undef EXTENDED_BLOCKS
#elif defined __3DS__ #elif defined __3DS__
#define CC_BUILD_CURL #define CC_BUILD_HTTPCLIENT
#define CC_BUILD_OPENAL #define CC_BUILD_OPENAL
#define CC_BUILD_3DS #define CC_BUILD_3DS
#undef CC_BUILD_FREETYPE #undef CC_BUILD_FREETYPE

View File

@ -124,5 +124,11 @@ enum CC_ERRORS {
NBT_ERR_EXPECTED_STR = 0xCCDED064UL, /* Expected String NBT tag */ NBT_ERR_EXPECTED_STR = 0xCCDED064UL, /* Expected String NBT tag */
NBT_ERR_EXPECTED_ARR = 0xCCDED065UL, /* Expected Byte Array NBT tag */ NBT_ERR_EXPECTED_ARR = 0xCCDED065UL, /* Expected Byte Array NBT tag */
NBT_ERR_ARR_TOO_SMALL= 0xCCDED066UL, /* Byte Array NBT tag length is < expected length */ NBT_ERR_ARR_TOO_SMALL= 0xCCDED066UL, /* Byte Array NBT tag length is < expected length */
HTTP_ERR_NO_SSL = 0xCCDED067UL, /* HTTP backend doesn't support SSL */
HTTP_ERR_REDIRECTS = 0xCCDED068UL, /* Too many attempted HTTP redirects */
HTTP_ERR_RELATIVE = 0xCCDED069UL, /* Unsupported relative URL format */
HTTP_ERR_INVALID_BODY= 0xCCDED06AUL, /* HTTP message doesn't have Content-Length or use Chunked transfer encoding */
HTTP_ERR_CHUNK_SIZE = 0xCCDED06BUL, /* HTTP message chunk has negative size/length */
}; };
#endif #endif

View File

@ -421,18 +421,17 @@ static cc_result HttpBackend_Do(struct HttpRequest* req, cc_string* url) {
#include "PackedCol.h" #include "PackedCol.h"
static void HttpBackend_Init(void) { static void HttpBackend_Init(void) {
httpOnly = true; // TODO: insecure //httpOnly = true; // TODO: insecure
} }
/* Components of a URL */ /* Components of a URL */
struct HttpUrl { struct HttpUrl {
cc_string address; /* Address of server (e.g. "classicube.net") */
cc_uint16 port; /* Port server is listening on (e.g 80) */
cc_bool https; /* Whether HTTPS or just HTTP protocol */ cc_bool https; /* Whether HTTPS or just HTTP protocol */
cc_string address; /* Address of server (e.g. "classicube.net:8080") */
cc_string resource; /* Path being accessed (and query string) */ cc_string resource; /* Path being accessed (and query string) */
char _addressBuffer[STRING_SIZE + 1]; char _addressBuffer[STRING_SIZE + 8];
char _resourceBuffer[STRING_SIZE * 4 + 1]; char _resourceBuffer[STRING_SIZE * 4];
}; };
static void HttpUrl_EncodeUrl(cc_string* dst, const cc_string* src) { static void HttpUrl_EncodeUrl(cc_string* dst, const cc_string* src) {
@ -455,30 +454,24 @@ static void HttpUrl_EncodeUrl(cc_string* dst, const cc_string* src) {
/* Splits up the components of a URL */ /* Splits up the components of a URL */
static void HttpUrl_Parse(const cc_string* src, struct HttpUrl* url) { static void HttpUrl_Parse(const cc_string* src, struct HttpUrl* url) {
cc_string scheme, path, addr, host, port, resource; cc_string scheme, path, addr, resource;
/* URL is of form [scheme]://[server host]:[server port]/[resource] */ /* URL is of form [scheme]://[server host]:[server port]/[resource] */
/* For simplicity, parsed as [scheme]://[server address]/[resource] */
int idx = String_IndexOfConst(src, "://"); int idx = String_IndexOfConst(src, "://");
scheme = idx == -1 ? String_Empty : String_UNSAFE_Substring(src, 0, idx); scheme = idx == -1 ? String_Empty : String_UNSAFE_Substring(src, 0, idx);
path = idx == -1 ? *src : String_UNSAFE_SubstringAt(src, idx + 3); path = idx == -1 ? *src : String_UNSAFE_SubstringAt(src, idx + 3);
url->https = String_CaselessEqualsConst(&scheme, "https"); url->https = String_CaselessEqualsConst(&scheme, "https");
String_UNSAFE_Separate(&path, '/', &addr, &resource); String_UNSAFE_Separate(&path, '/', &addr, &resource);
String_UNSAFE_Separate(&addr, ':', &host, &port);
String_InitArray_NT(url->address, url->_addressBuffer); String_InitArray(url->address, url->_addressBuffer);
String_Copy(&url->address, &host); String_Copy(&url->address, &addr);
url->_addressBuffer[url->address.length] = '\0';
if (!Convert_ParseUInt16(&port, &url->port)) { String_InitArray(url->resource, url->_resourceBuffer);
url->port = url->https ? 443 : 80;
}
String_InitArray_NT(url->resource, url->_resourceBuffer);
String_Append(&url->resource, '/'); String_Append(&url->resource, '/');
/* Address may have unicode characters - need to percent encode them */ /* Address may have unicode characters - need to percent encode them */
HttpUrl_EncodeUrl(&url->resource, &resource); HttpUrl_EncodeUrl(&url->resource, &resource);
url->_resourceBuffer[url->resource.length] = '\0';
} }
@ -487,8 +480,18 @@ struct HttpConnection {
}; };
static cc_result HttpConnection_Open(struct HttpConnection* conn, const struct HttpUrl* url) { static cc_result HttpConnection_Open(struct HttpConnection* conn, const struct HttpUrl* url) {
cc_string host, port;
cc_uint16 portNum;
/* address can be either "host" or "host:port" */
String_UNSAFE_Separate(&url->address, ':', &host, &port);
if (!Convert_ParseUInt16(&port, &portNum)) {
portNum = url->https ? 443 : 80;
}
conn->socket = 0; conn->socket = 0;
return Socket_Connect(&conn->socket, &url->address, url->port, false); if (url->https) return HTTP_ERR_NO_SSL;
return Socket_Connect(&conn->socket, &host, portNum, false);
} }
static void HttpConnection_Close(struct HttpConnection* conn) { static void HttpConnection_Close(struct HttpConnection* conn) {
@ -545,7 +548,7 @@ static void HttpClient_Serialise(struct HttpClientState* state) {
String_Format2(buffer, "%c %s HTTP/1.1\r\n", String_Format2(buffer, "%c %s HTTP/1.1\r\n",
verbs[req->requestType], &state->url.resource); verbs[req->requestType], &state->url.resource);
Http_AddHeader(req, "Host", &state->url.address); /* TODO port for non-standard*/ Http_AddHeader(req, "Host", &state->url.address);
Http_AddHeader(req, "User-Agent", &userAgent); Http_AddHeader(req, "User-Agent", &userAgent);
if (req->data) String_Format1(buffer, "Content-Length: %i\r\n", &req->size); if (req->data) String_Format1(buffer, "Content-Length: %i\r\n", &req->size);
@ -569,7 +572,7 @@ static cc_result HttpClient_SendRequest(struct HttpClientState* state) {
http_curProgress = HTTP_PROGRESS_FETCHING_DATA; http_curProgress = HTTP_PROGRESS_FETCHING_DATA;
HttpClient_Serialise(state); HttpClient_Serialise(state);
/* TODO check wrote is >= inputMsg.length */ /* TODO check that wrote is >= inputMsg.length */
return Socket_Write(state->conn.socket, inputBuffer, inputMsg.length, &wrote); return Socket_Write(state->conn.socket, inputBuffer, inputMsg.length, &wrote);
} }
@ -653,8 +656,7 @@ static cc_result HttpClient_Process(struct HttpClientState* state, char* buffer,
Http_BufferInit(req); Http_BufferInit(req);
state->state = HTTP_RESPONSE_STATE_BODY_DATA; state->state = HTTP_RESPONSE_STATE_BODY_DATA;
} else { } else {
/* Chunked encoding not supported yet */ return HTTP_ERR_INVALID_BODY;
return ERR_NOT_SUPPORTED;
} }
} }
break; break;
@ -685,7 +687,7 @@ static cc_result HttpClient_Process(struct HttpClientState* state, char* buffer,
if (c != '\n') { String_Append(&state->header, c); continue; } if (c != '\n') { String_Append(&state->header, c); continue; }
state->chunkLength = HttpClient_GetChunkLength(&state->header); state->chunkLength = HttpClient_GetChunkLength(&state->header);
if (state->chunkLength < 0) return ERR_INVALID_ARGUMENT; if (state->chunkLength < 0) return HTTP_ERR_CHUNK_SIZE;
state->header.length = 0; state->header.length = 0;
if (state->chunkLength == 0) { if (state->chunkLength == 0) {
@ -787,7 +789,7 @@ static cc_result HttpClient_HandleRedirect(struct HttpClientState* state) {
state->req->contentLength = 0; /* TODO */ state->req->contentLength = 0; /* TODO */
return 0; return 0;
} else { } else {
return ERR_INVALID_ARGUMENT; return HTTP_ERR_RELATIVE;
} }
} }
@ -816,8 +818,7 @@ static cc_result HttpBackend_Do(struct HttpRequest* req, cc_string* urlStr) {
HttpConnection_Close(&state.conn); HttpConnection_Close(&state.conn);
if (res || !HttpClient_IsRedirect(req)) break; if (res || !HttpClient_IsRedirect(req)) break;
/* TODO BETTER ERROR CODE */ if (redirects >= 20) return HTTP_ERR_REDIRECTS;
if (redirects >= 20) return ERR_DOWNLOAD_INVALID;
/* TODO FOLLOW LOCATION PROPERLY */ /* TODO FOLLOW LOCATION PROPERLY */
redirects++; redirects++;

View File

@ -98,6 +98,8 @@ static const char* GetCCErrorDesc(cc_result res) {
case NBT_ERR_EXPECTED_STR: return "Expected String NBT tag"; case NBT_ERR_EXPECTED_STR: return "Expected String NBT tag";
case NBT_ERR_EXPECTED_ARR: return "Expected ByteArray NBT tag"; case NBT_ERR_EXPECTED_ARR: return "Expected ByteArray NBT tag";
case NBT_ERR_ARR_TOO_SMALL:return "ByteArray NBT tag too small"; case NBT_ERR_ARR_TOO_SMALL:return "ByteArray NBT tag too small";
case HTTP_ERR_NO_SSL: return "HTTPS URLs are not currently supported";
} }
return NULL; return NULL;
} }