int httpGet(const char* url, u8** buf, u32* size) { httpcContext context; CHECK(httpcOpenContext(&context, HTTPC_METHOD_GET, (char*)url, 0), "Could not open HTTP context"); // Add User Agent field (required by Github API calls) CHECK(httpcAddRequestHeaderField(&context, (char*)"User-Agent", (char*)"ARN-UPDATER"), "Could not set User Agent"); CHECK(httpcBeginRequest(&context), "Could not begin request"); // Add root CA required for Github and AWS URLs CHECK(httpcAddTrustedRootCA(&context, digicert_cer, digicert_cer_len), "Could not add Digicert root CA"); CHECK(httpcAddTrustedRootCA(&context, cybertrust_cer, cybertrust_cer_len), "Could not add Cybertrust root CA"); u32 statuscode = 0; CHECK(httpcGetResponseStatusCode(&context, &statuscode, 0), "Could not get status code"); if (statuscode != 200) { // Handle 3xx codes if (statuscode >= 300 && statuscode < 400) { char newUrl[1024]; CHECK(httpcGetResponseHeader(&context, (char*)"Location", newUrl, 1024), "Could not get Location header for 3xx reply"); CHECK(httpcCloseContext(&context), "Could not close HTTP context"); return httpGet(newUrl, buf, size); } throw formatErrMessage("Non-200 status code", statuscode); } CHECK(httpcGetDownloadSizeState(&context, NULL, size), "Could not get file size"); *buf = (u8*)std::malloc(*size); if (*buf == NULL) throw formatErrMessage("Could not allocate enough memory", *size); std::memset(*buf, 0, *size); CHECK(httpcDownloadData(&context, *buf, *size, NULL), "Could not download data"); CHECK(httpcCloseContext(&context), "Could not close HTTP context"); return 1; }
/*** Add a trusted RootCA cert to a context. @function :addTrustedRootCA @tparam string DER certificate @treturn[1] boolean `true` if everything went fine @treturn[2] boolean `false` in case of error @treturn[2] integer error code */ static int httpc_addTrustedRootCA(lua_State *L) { httpcContext *context = lua_touserdata(L, 1); u32 certsize; u8* cert = (u8*)luaL_checklstring(L, 2, (size_t*)&certsize); Result ret = httpcAddTrustedRootCA(context, cert, certsize); if (ret != 0) { lua_pushboolean(L, false); lua_pushinteger(L, ret); return 2; } lua_pushboolean(L, true); return 1; }
Result download_config(char *url, u8 *cert, u32 certsize, u8 *filebuffer, u32 dlsize, u32 *out_statuscode) { Result ret=0; u32 statuscode=0; httpcContext context; ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1); if(R_FAILED(ret)) { printf("httpcOpenContext returned 0x%08x.\n", (unsigned int)ret); return ret; } ret = httpcAddRequestHeaderField(&context, "User-Agent", "ctr-httpwn/"VERSION); if(R_FAILED(ret)) { printf("httpcAddRequestHeaderField returned 0x%08x.\n", (unsigned int)ret); httpcCloseContext(&context); return ret; } ret = httpcAddTrustedRootCA(&context, cert, certsize); if(R_FAILED(ret)) { printf("httpcAddTrustedRootCA returned 0x%08x.\n", (unsigned int)ret); httpcCloseContext(&context); return ret; } ret = httpcBeginRequest(&context); if(R_FAILED(ret)) { printf("httpcBeginRequest returned 0x%08x.\n", (unsigned int)ret); httpcCloseContext(&context); return ret; } ret = httpcGetResponseStatusCode(&context, &statuscode, 0); if(R_FAILED(ret)) { printf("httpcGetResponseStatusCode returned 0x%08x.\n", (unsigned int)ret); httpcCloseContext(&context); return ret; } if(out_statuscode)*out_statuscode = statuscode; if(statuscode==200 || statuscode==500) { ret = httpcDownloadData(&context, filebuffer, dlsize, NULL); if(ret!=0 && statuscode==200) { printf("httpcDownloadData returned 0x%08x.\n", (unsigned int)ret); httpcCloseContext(&context); return ret; } } ret = httpcCloseContext(&context); if(R_FAILED(ret)) { printf("httpcCloseContext returned 0x%08x.\n", (unsigned int)ret); return ret; } if(statuscode!=200) { printf("Invalid statuscode: %u.\n", (unsigned int)statuscode); return -5; } return 0; }