Как скачать и сохранить файл с HTTP-сервера в C - PullRequest
0 голосов
/ 10 февраля 2019

Мне нужно скачать и сохранить файл с HTTP-сервера, но я НЕ МОГУ * использовать libcurl или любые встроенные системные библиотеки.Это программа для Nintendo 3ds, которую можно запустить с помощью homebrew (я использую devkitpro, если вам интересно).Мой текущий код работает только тогда, когда я вручную набираю аргументы для своей функции загрузки:

http_download_save("https://web.com/file.txt", "output-file-name.txt"); // <-- WORKS

char url[64] = "https://web.com/file.txt";
char out[64] = "output-file-name.txt";
http_download_save(url, out); // <-- DOESNT WORK, No errors occur but it does not download the file

Примечание к URL-адресу char и char, когда у меня была длина на 248 (это то, что раньше было) Windows выдал ошибку, когда я попытался удалить файл, сказав, что имя было слишком длинным, и хотя изменение его на 64 не помогло, загрузка все равно не удалась.Когда я вручную набираю URL, но использую переменную для имени выходного файла, он создает поврежденный файл.Вот код для моей функции загрузки:

Result http_download_save(char *url, char *outfile)
{
    Result ret=0;
    httpcContext context;
    char *newurl=NULL;
    u32 statuscode=0;
    u32 contentsize=0, readsize=0, size=0;
    u8 *buf, *lastbuf;

    do {
        ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1);

        // This disables SSL cert verification, so https:// will be usable
        ret = httpcSetSSLOpt(&context, SSLCOPT_DisableVerify);

        // Enable Keep-Alive connections
        ret = httpcSetKeepAlive(&context, HTTPC_KEEPALIVE_ENABLED);

        // Set a User-Agent header so websites can identify your application
        ret = httpcAddRequestHeaderField(&context, "User-Agent", "httpc-example/1.0.0");

        // Tell the server we can support Keep-Alive connections.
        // This will delay connection teardown momentarily (typically 5s)
        // in case there is another request made to the same server.
        ret = httpcAddRequestHeaderField(&context, "Connection", "Keep-Alive");

        ret = httpcBeginRequest(&context);
        if(ret!=0){
            httpcCloseContext(&context);
            if(newurl!=NULL) free(newurl);
            return ret;
        }

        ret = httpcGetResponseStatusCode(&context, &statuscode);
        if(ret!=0){
            httpcCloseContext(&context);
            if(newurl!=NULL) free(newurl);
            return ret;
        }

        if ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)) {
            if(newurl==NULL) newurl = (char*)malloc(0x1000); // One 4K page for new URL
            if (newurl==NULL){
                httpcCloseContext(&context);
                return -1;
            }
            ret = httpcGetResponseHeader(&context, "Location", newurl, 0x1000);
            url = newurl; // Change pointer to the url that we just learned
            printf("redirecting to url: %s\n",url);
            httpcCloseContext(&context); // Close this context before we try the next
        }
    } while ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308));

    if(statuscode!=200){
        printf("\x1b[31mAn Error Occured\x1b[0m\n");
        httpcCloseContext(&context);
        if(newurl!=NULL) free(newurl);
        return -2;
    }

    // This relies on an optional Content-Length header and may be 0
    ret=httpcGetDownloadSizeState(&context, NULL, &contentsize);
    if(ret!=0){
        httpcCloseContext(&context);
        if(newurl!=NULL) free(newurl);
        return ret;
    }

    // Start with a single page buffer
    buf = (u8*)malloc(0x1000);
    if(buf==NULL){
        httpcCloseContext(&context);
        if(newurl!=NULL) free(newurl);
        return -1;
    }

    do {
        // This download loop resizes the buffer as data is read.
        ret = httpcDownloadData(&context, buf+size, 0x1000, &readsize);
        size += readsize; 
        if (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING){
            lastbuf = buf; // Save the old pointer, in case realloc() fails.
            buf = (u8*)realloc(buf, size + 0x1000);
            if(buf==NULL){ 
                httpcCloseContext(&context);
                free(lastbuf);
                if(newurl!=NULL) free(newurl);
                return -1;
            }
        }
    } while (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING); 

    if(ret!=0){
        httpcCloseContext(&context);
        if(newurl!=NULL) free(newurl);
        free(buf);
        return -1;
    }

    FILE* out = fopen(outfile, "w");
    fwrite(buf, 1, size, out);
    fclose(out);

    httpcCloseContext(&context);
    free(buf);
    if (newurl!=NULL) free(newurl);

    return 0;
}

Заранее спасибо!

...