Result http_getactual_payloadurl(char *requrl, char *outurl, u32 outurl_maxsize) { Result ret=0; httpcContext context; ret = httpcOpenContext(&context, requrl, 1); if(ret!=0)return ret; ret = httpcAddRequestHeaderField(&context, "User-Agent", "hblauncher_loader/"VERSION); if(ret!=0) { httpcCloseContext(&context); return ret; } ret = httpcBeginRequest(&context); if(ret!=0) { httpcCloseContext(&context); return ret; } ret = httpcGetResponseHeader(&context, "Location", outurl, outurl_maxsize); httpcCloseContext(&context); return 0; }
/*** Add a field in the request header. @function :addRequestHeaderField @tparam string name Name of the field @tparam string value Value of the field @treturn[1] boolean `true` if everything went fine @treturn[2] boolean `false` in case of error @treturn[2] integer error code */ static int httpc_addRequestHeaderField(lua_State *L) { httpcContext *context = lua_touserdata(L, 1); char *name = (char*)luaL_checkstring(L, 2); char *value = (char*)luaL_checkstring(L, 3); Result ret = httpcAddRequestHeaderField(context, name ,value); if (ret != 0) { lua_pushboolean(L, false); lua_pushinteger(L, ret); return 2; } lua_pushboolean(L, true); return 1; }
Result get_redirect(char *url, char *out, size_t out_size, char *user_agent) { Result ret; httpcContext context; ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 0); if(R_FAILED(ret)) return ret; ret = httpcAddRequestHeaderField(&context, "User-Agent", user_agent); if(R_SUCCEEDED(ret)) ret = httpcBeginRequest(&context); if(R_FAILED(ret)) { httpcCloseContext(&context); return ret; } ret = httpcGetResponseHeader(&context, "Location", out, out_size); httpcCloseContext(&context); return ret; }
Result download_file(httpcContext *context, void** buffer, size_t* size, char* user_agent) { Result ret; ret = httpcAddRequestHeaderField(context, "User-Agent", user_agent); if(R_FAILED(ret)) return ret; ret = httpcBeginRequest(context); if(R_FAILED(ret)) return ret; u32 status_code = 0; ret = httpcGetResponseStatusCode(context, &status_code); if(R_FAILED(ret)) return ret; if(status_code != 200) return -1; u32 sz = 0; ret = httpcGetDownloadSizeState(context, NULL, &sz); if(R_FAILED(ret)) return ret; void* buf = malloc(sz); if(!buf) return -2; memset(buf, 0, sz); ret = httpcDownloadData(context, buf, sz, NULL); if(R_FAILED(ret)) { free(buf); return ret; } if(size) *size = sz; if(buffer) *buffer = buf; else free(buf); return 0; }
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; }
Result http_download_payload(char *url, u32 *payloadsize) { Result ret=0; u32 statuscode=0; u32 contentsize=0; httpcContext context; ret = httpcOpenContext(&context, url, 1); if(ret!=0)return ret; ret = httpcAddRequestHeaderField(&context, "User-Agent", "hblauncher_loader/"VERSION); if(ret!=0) { httpcCloseContext(&context); return ret; } ret = httpcBeginRequest(&context); if(ret!=0) { httpcCloseContext(&context); return ret; } ret = httpcGetResponseStatusCode(&context, &statuscode, 0); if(ret!=0) { httpcCloseContext(&context); return ret; } if(statuscode!=200) { printf("Error: server returned HTTP statuscode %u.\n", (unsigned int)statuscode); httpcCloseContext(&context); return -2; } ret=httpcGetDownloadSizeState(&context, NULL, &contentsize); if(ret!=0) { httpcCloseContext(&context); return ret; } if(contentsize==0 || contentsize>PAYLOAD_TEXTMAXSIZE) { printf("Invalid HTTP content-size: 0x%08x.\n", (unsigned int)contentsize); ret = -3; httpcCloseContext(&context); return ret; } ret = httpcDownloadData(&context, filebuffer, contentsize, NULL); if(ret!=0) { httpcCloseContext(&context); return ret; } httpcCloseContext(&context); *payloadsize = contentsize; return 0; }
static Result action_url_install_open_src(void* data, u32 index, u32* handle) { url_install_data* installData = (url_install_data*) data; Result res = 0; httpcContext* context = (httpcContext*) calloc(1, sizeof(httpcContext)); if(context != NULL) { if(R_SUCCEEDED(res = httpcOpenContext(context, HTTPC_METHOD_GET, installData->urls[index], 1))) { char userAgent[128]; snprintf(userAgent, sizeof(userAgent), "Mozilla/5.0 (Nintendo 3DS; Mobile; rv:10.0) Gecko/20100101 FBI/%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO); if(R_SUCCEEDED(res = httpcSetSSLOpt(context, SSLCOPT_DisableVerify)) && R_SUCCEEDED(res = httpcAddRequestHeaderField(context, "User-Agent", userAgent)) && R_SUCCEEDED(res = httpcBeginRequest(context)) && R_SUCCEEDED(res = httpcGetResponseStatusCode(context, &installData->responseCode, 0))) { if(installData->responseCode == 200) { *handle = (u32) context; } else if(installData->responseCode == 301 || installData->responseCode == 302 || installData->responseCode == 303) { memset(installData->urls[index], '\0', URL_MAX); if(R_SUCCEEDED(res = httpcGetResponseHeader(context, "Location", installData->urls[index], URL_MAX))) { httpcCloseContext(context); free(context); return action_url_install_open_src(data, index, handle); } } else { res = R_FBI_HTTP_RESPONSE_CODE; } } if(R_FAILED(res)) { httpcCloseContext(context); } } if(R_FAILED(res)) { free(context); } } else { res = R_FBI_OUT_OF_MEMORY; } return res; }
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; }
Result http_haxx(char *requrl, u8 *cert, u32 certsize, targeturlctx *first_targeturlctx) { Result ret=0; httpcContext context; u32 *linearaddr = NULL; Handle httpheap_sharedmem_handle=0; Handle ropvmem_sharedmem_handle=0; Handle httpc_sslc_handle = 0; u32 i; ret = httpcOpenContext(&context, HTTPC_METHOD_POST, requrl, 1); if(ret!=0)return ret; ret = httpcAddPostDataAscii(&context, "form_name", "form_value"); if(ret!=0) { httpcCloseContext(&context); return ret; } //Locate the physmem for the httpc sharedmem. With the current cmpblock, there can only be one POST struct that was ever written into sharedmem, with the name/value from above. printf("Searching for the httpc sharedmem in physmem...\n"); ret = locate_sharedmem_linearaddr(&linearaddr); if(ret!=0) { printf("Failed to locate the sharedmem in physmem.\n"); httpcCloseContext(&context); return ret; } printf("Writing the haxx to physmem...\n"); ret = writehax_sharedmem_physmem(linearaddr); if(ret!=0) { printf("Failed to setup the haxx.\n"); httpcCloseContext(&context); return ret; } printf("Triggering the haxx...\n"); ret = _httpcCloseContext(&context, &httpheap_sharedmem_handle, &ropvmem_sharedmem_handle, &httpc_sslc_handle); if(R_FAILED(ret)) { printf("httpcCloseContext returned 0x%08x.\n", (unsigned int)ret); return ret; } httpheap_sharedmem = (vu32*)mappableAlloc(httpheap_size); if(httpheap_sharedmem==NULL) { ret = -2; svcCloseHandle(httpheap_sharedmem_handle); svcCloseHandle(ropvmem_sharedmem_handle); svcCloseHandle(httpc_sslc_handle); return ret; } ropvmem_sharedmem = (vu32*)mappableAlloc(ropvmem_size); if(ropvmem_sharedmem==NULL) { ret = -3; mappableFree((void*)httpheap_sharedmem); svcCloseHandle(httpheap_sharedmem_handle); svcCloseHandle(ropvmem_sharedmem_handle); svcCloseHandle(httpc_sslc_handle); return ret; } if(R_FAILED(ret=svcMapMemoryBlock(httpheap_sharedmem_handle, (u32)httpheap_sharedmem, MEMPERM_READ | MEMPERM_WRITE, MEMPERM_READ | MEMPERM_WRITE))) { svcCloseHandle(httpheap_sharedmem_handle); mappableFree((void*)httpheap_sharedmem); httpheap_sharedmem = NULL; svcCloseHandle(ropvmem_sharedmem_handle); mappableFree((void*)ropvmem_sharedmem); ropvmem_sharedmem = NULL; svcCloseHandle(httpc_sslc_handle); printf("svcMapMemoryBlock with the httpheap sharedmem failed: 0x%08x.\n", (unsigned int)ret); return ret; } if(R_FAILED(ret=svcMapMemoryBlock(ropvmem_sharedmem_handle, (u32)ropvmem_sharedmem, MEMPERM_READ | MEMPERM_WRITE, MEMPERM_READ | MEMPERM_WRITE))) { svcUnmapMemoryBlock(httpheap_sharedmem_handle, (u32)httpheap_sharedmem); svcCloseHandle(httpheap_sharedmem_handle); mappableFree((void*)httpheap_sharedmem); httpheap_sharedmem = NULL; svcCloseHandle(ropvmem_sharedmem_handle); mappableFree((void*)ropvmem_sharedmem); ropvmem_sharedmem = NULL; svcCloseHandle(httpc_sslc_handle); printf("svcMapMemoryBlock with the ropvmem sharedmem failed: 0x%08x.\n", (unsigned int)ret); return ret; } printf("Finishing haxx setup with sysmodule memory...\n"); ret = setuphaxx_httpheap_sharedmem(first_targeturlctx); if(R_FAILED(ret)) { printf("Failed to finish haxx setup: 0x%08x.\n", (unsigned int)ret); } else { printf("Finalizing...\n"); } svcUnmapMemoryBlock(httpheap_sharedmem_handle, (u32)httpheap_sharedmem); svcCloseHandle(httpheap_sharedmem_handle); mappableFree((void*)httpheap_sharedmem); httpheap_sharedmem = NULL; svcUnmapMemoryBlock(ropvmem_sharedmem_handle, (u32)ropvmem_sharedmem); svcCloseHandle(ropvmem_sharedmem_handle); mappableFree((void*)ropvmem_sharedmem); ropvmem_sharedmem = NULL; if(R_FAILED(ret)) { svcCloseHandle(httpc_sslc_handle); return ret; } printf("Running setup with sslc...\n"); ret = setuphax_http_sslc(httpc_sslc_handle, cert, certsize); svcCloseHandle(httpc_sslc_handle);//Normally sslcExit should close this, but close it here too just in case. if(R_FAILED(ret)) { printf("Setup failed with sslc: 0x%08x.\n", (unsigned int)ret); return ret; } printf("Testing httpc with non-targeted URLs...\n"); for(i=0; i<2; i++) { ret = httpcOpenContext(&context, HTTPC_METHOD_POST, requrl, 1); if(R_FAILED(ret)) { printf("httpcOpenContext returned 0x%08x, i=%u.\n", (unsigned int)ret, (unsigned int)i); return ret; } ret = httpcAddRequestHeaderField(&context, "User-Agent", "ctr-httpwn/"VERSION); if(R_FAILED(ret)) { printf("httpcAddRequestHeaderField returned 0x%08x, i=%u.\n", (unsigned int)ret, (unsigned int)i); httpcCloseContext(&context); return ret; } ret = httpcAddPostDataAscii(&context, "form_name", "form_value"); if(R_FAILED(ret)) { printf("httpcAddPostDataAscii returned 0x%08x, i=%u.\n", (unsigned int)ret, (unsigned int)i); httpcCloseContext(&context); return ret; } ret = httpcCloseContext(&context); if(R_FAILED(ret)) { printf("httpcCloseContext returned 0x%08x, i=%u.\n", (unsigned int)ret, (unsigned int)i); return ret; } } return 0; }
static int lua_downstring(lua_State *L){ int argc = lua_gettop(L); #ifndef SKIP_ERROR_HANDLING if (argc < 1 || argc > 4) return luaL_error(L, "wrong number of arguments"); #endif const char* url = luaL_checkstring(L,1); const char* headers = (argc >= 2) ? luaL_checkstring(L,2) : NULL; u8 method = (argc >= 3) ? luaL_checkinteger(L,3) : 0; const char* postdata = (argc >= 4) ? luaL_checkstring(L,4) : NULL; httpcContext context; HTTPC_RequestMethod useMethod = HTTPC_METHOD_GET; if(method <= 3 && method >= 1) useMethod = (HTTPC_RequestMethod)method; u32 statuscode=0; do { if (statuscode >= 301 && statuscode <= 308) { char newurl[4096]; httpcGetResponseHeader(&context, (char*)"Location", &newurl[0], 4096); url = &newurl[0]; httpcCloseContext(&context); } Result ret = httpcOpenContext(&context, useMethod, (char*)url , 0); // Lets just disable SSL verification instead of loading default certs. httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); if(headers != NULL){ char *tokenheader = (char*)malloc(strlen(headers)+1); strcpy(tokenheader, headers); char *toker = tokenheader; char *headername = NULL; char *headervalue = NULL; do { headername = strtok(toker, ":"); if (headername == NULL) break; headervalue = strtok(NULL, "\n"); if (headervalue == NULL) break; if (headervalue[0] == ' ') headervalue++; httpcAddRequestHeaderField(&context, headername, headervalue); toker = NULL; } while (headername != NULL && headervalue != NULL); free(tokenheader); } if (useMethod == HTTPC_METHOD_POST && postdata != NULL) { httpcAddPostDataRaw(&context, (u32*)postdata, strlen(postdata)); } #ifndef SKIP_ERROR_HANDLING if(ret==0){ #endif httpcBeginRequest(&context); long int contentsize=0; // Crash on the += if u32. WTF? u32 readSize=0; httpcGetResponseStatusCode(&context, &statuscode, 0); if (statuscode == 200) { unsigned char *buffer = (unsigned char*)malloc(0x1000); do { ret = httpcDownloadData(&context, buffer+contentsize, 0x1000, &readSize); contentsize += readSize; if (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING) buffer = (unsigned char*)realloc(buffer, contentsize + 0x1000); } while (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING); buffer = (unsigned char*)realloc(buffer, contentsize + 1); buffer[contentsize] = 0; lua_pushlstring(L,(const char*)buffer,contentsize); free(buffer); } #ifndef SKIP_ERROR_HANDLING } #endif } while ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)); #ifndef SKIP_ERROR_HANDLING if ((statuscode < 200 && statuscode > 226) && statuscode != 304) luaL_error(L, "error opening url"); #endif httpcCloseContext(&context); return 1; }
static int lua_download(lua_State *L){ int argc = lua_gettop(L); #ifndef SKIP_ERROR_HANDLING if (argc < 2 || argc > 5) return luaL_error(L, "wrong number of arguments"); #endif const char* url = luaL_checkstring(L,1); const char* file = luaL_checkstring(L,2); const char* headers = (argc >= 3) ? luaL_checkstring(L,3) : NULL; u8 method = (argc >= 4) ? luaL_checkinteger(L,4) : 0; const char* postdata = (argc >= 5) ? luaL_checkstring(L,5) : NULL; httpcContext context; u32 statuscode=0; HTTPC_RequestMethod useMethod = HTTPC_METHOD_GET; if(method <= 3 && method >= 1) useMethod = (HTTPC_RequestMethod)method; do { if (statuscode >= 301 && statuscode <= 308) { char newurl[4096]; httpcGetResponseHeader(&context, (char*)"Location", &newurl[0], 4096); url = &newurl[0]; httpcCloseContext(&context); } Result ret = httpcOpenContext(&context, useMethod, (char*)url, 0); // Just disable SSL verification instead of loading default certs. httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); if(headers != NULL){ char *tokenheader = (char*)malloc(strlen(headers)+1); strcpy(tokenheader, headers); char *toker = tokenheader; char *headername = NULL; char *headervalue = NULL; do { headername = strtok(toker, ":"); if (headername == NULL) break; headervalue = strtok(NULL, "\n"); if (headervalue == NULL) break; if (headervalue[0] == ' ') headervalue++; httpcAddRequestHeaderField(&context, headername, headervalue); toker = NULL; } while (headername != NULL && headervalue != NULL); free(tokenheader); } if (useMethod == HTTPC_METHOD_POST && postdata != NULL) { httpcAddPostDataRaw(&context, (u32*)postdata, strlen(postdata)); } #ifndef SKIP_ERROR_HANDLING if(ret==0){ #endif httpcBeginRequest(&context); u32 contentsize=0; httpcGetResponseStatusCode(&context, &statuscode, 0); if (statuscode == 200){ u32 readSize = 0; long int bytesWritten = 0; u8* buf = (u8*)malloc(0x1000); memset(buf, 0, 0x1000); Handle fileHandle; FS_Archive sdmcArchive=(FS_Archive){ARCHIVE_SDMC, (FS_Path){PATH_EMPTY, 1, (u8*)""}}; FS_Path filePath=fsMakePath(PATH_ASCII, file); FSUSER_OpenFileDirectly( &fileHandle, sdmcArchive, filePath, FS_OPEN_CREATE|FS_OPEN_WRITE, 0x00000000); do { ret = httpcDownloadData(&context, buf, 0x1000, &readSize); FSFILE_Write(fileHandle, NULL, bytesWritten, buf, readSize, 0x10001); bytesWritten += readSize; } while (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING); FSFILE_Close(fileHandle); svcCloseHandle(fileHandle); free(buf); } #ifndef SKIP_ERROR_HANDLING } #endif } while ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)); #ifndef SKIP_ERROR_HANDLING if ((statuscode < 200 && statuscode > 226) && statuscode != 304) luaL_error(L, "error opening url"); #endif httpcCloseContext(&context); lua_pushinteger(L, statuscode); return 1; }