コード例 #1
0
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;
}
コード例 #2
0
ファイル: httpc.c プロジェクト: ctruLua/ctruLua
/***
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;
}
コード例 #3
0
ファイル: main.c プロジェクト: Dazzozo/salt_sploit_installer
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;
}
コード例 #4
0
ファイル: main.c プロジェクト: Dazzozo/salt_sploit_installer
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;
}
コード例 #5
0
ファイル: http.cpp プロジェクト: pychi/lumaupdate
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;
}
コード例 #6
0
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;
}
コード例 #7
0
ファイル: urlinstall.c プロジェクト: rychenga/FBI
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;
}
コード例 #8
0
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;
}
コード例 #9
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;
}
コード例 #10
0
ファイル: luaNetwork.cpp プロジェクト: Rinnegatamante/lpp-3ds
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;
}
コード例 #11
0
ファイル: luaNetwork.cpp プロジェクト: Rinnegatamante/lpp-3ds
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;
}