|
1 | 1 | #include "download.h" |
2 | | - |
3 | | -Result downloadToBuffer(const char * url, u8 ** buf, u32 * bufsize) |
4 | | -{ |
5 | 2 |
|
6 | | - httpcContext context; |
| 3 | +Result setupContext(httpcContext * context, const char * url, u32 * size) |
| 4 | +{ |
7 | 5 | Result ret = 0; |
8 | | - char * newurl = NULL; |
9 | 6 | u32 statuscode = 0; |
10 | | - u32 contentsize = 0, readsize = 0, size = 0; |
11 | | - u8 * lastbuf = NULL; |
12 | 7 |
|
13 | | - do { |
14 | | - ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1); |
15 | | - ret = httpcAddRequestHeaderField(&context, "User-Agent", "MultiUpdater"); |
16 | | - if (ret != 0) { |
17 | | - httpcCloseContext(&context); |
18 | | - if (newurl != NULL) free(newurl); |
19 | | - printf("Error in:\nhttpcAddRequestHeaderField\nreturn: %lx\n", ret); |
20 | | - return ret; |
| 8 | + ret = httpcOpenContext(context, HTTPC_METHOD_GET, url, 1); |
| 9 | + if (ret != 0) { |
| 10 | + printf("Error in:\nhttpcOpenContext\n"); |
| 11 | + httpcCloseContext(context); |
| 12 | + return ret; |
| 13 | + } |
| 14 | + |
| 15 | + ret = httpcAddRequestHeaderField(context, "User-Agent", "MultiUpdater"); |
| 16 | + if (ret != 0) { |
| 17 | + printf("Error in:\nhttpcAddRequestHeaderField\n"); |
| 18 | + httpcCloseContext(context); |
| 19 | + return ret; |
| 20 | + } |
| 21 | + |
| 22 | + ret = httpcSetSSLOpt(context, SSLCOPT_DisableVerify); |
| 23 | + if (ret != 0) { |
| 24 | + printf("Error in:\nhttpcSetSSLOpt\n"); |
| 25 | + httpcCloseContext(context); |
| 26 | + return ret; |
| 27 | + } |
| 28 | + |
| 29 | + ret = httpcAddRequestHeaderField(context, "Connection", "Keep-Alive"); |
| 30 | + if (ret != 0) { |
| 31 | + printf("Error in:\nhttpcAddRequestHeaderField\n"); |
| 32 | + httpcCloseContext(context); |
| 33 | + return ret; |
| 34 | + } |
| 35 | + |
| 36 | + ret = httpcBeginRequest(context); |
| 37 | + if (ret != 0) { |
| 38 | + printf("Error in:\nhttpcBeginRequest\n"); |
| 39 | + httpcCloseContext(context); |
| 40 | + return ret; |
| 41 | + } |
| 42 | + |
| 43 | + ret = httpcGetResponseStatusCode(context, &statuscode); |
| 44 | + if (ret != 0) { |
| 45 | + printf("Error in:\nhttpcGetResponseStatusCode\n"); |
| 46 | + httpcCloseContext(context); |
| 47 | + return ret; |
| 48 | + } |
| 49 | + |
| 50 | + if ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)) { |
| 51 | + char * newurl = malloc(0x1000); // One 4K page for new URL |
| 52 | + if (newurl == NULL) { |
| 53 | + httpcCloseContext(context); |
| 54 | + return DL_ERROR_ALLOC; |
21 | 55 | } |
22 | 56 |
|
23 | | - ret = httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); |
24 | | - ret = httpcAddRequestHeaderField(&context, "Connection", "Keep-Alive"); |
25 | | - |
26 | | - ret = httpcBeginRequest(&context); |
| 57 | + ret = httpcGetResponseHeader(context, "Location", newurl, 0x1000); |
27 | 58 | if (ret != 0) { |
28 | | - httpcCloseContext(&context); |
29 | | - if (newurl != NULL) free(newurl); |
30 | | - printf("Error in:\nhttpcBeginRequest\nreturn: %lx\n", ret); |
| 59 | + printf("Error in:\nhttpcGetResponseHeader\n"); |
| 60 | + httpcCloseContext(context); |
| 61 | + free(newurl); |
31 | 62 | return ret; |
32 | 63 | } |
33 | 64 |
|
34 | | - ret = httpcGetResponseStatusCode(&context, &statuscode); |
35 | | - if (ret != 0) { |
36 | | - printf("Error in:\nhttpcGetResponseStatusCode\nreturn: %lx\n", ret); |
37 | | - httpcCloseContext(&context); |
38 | | - if (newurl != NULL) free(newurl); |
39 | | - return ret; |
40 | | - } |
| 65 | + httpcCloseContext(context); // Close this context before we try the next |
41 | 66 |
|
42 | | - if ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)) { |
43 | | - if (newurl == NULL) newurl = malloc(0x1000); // One 4K page for new URL |
44 | | - if (newurl == NULL) { |
45 | | - httpcCloseContext(&context); |
46 | | - return -1; |
47 | | - } |
48 | | - |
49 | | - ret = httpcGetResponseHeader(&context, "Location", newurl, 0x1000); |
50 | | - httpcCloseContext(&context); // Close this context before we try the next |
51 | | - |
52 | | - if (newurl[0] == '/') { //if the url starts with a slash, it's local |
53 | | - int slashpos = 0; |
54 | | - char * domainname = strdup(url); |
55 | | - if (strncmp("http", domainname, 4) == 0) slashpos = 7; //if the url in the entry starts with http:// or https:// we need to skip that |
56 | | - slashpos += (int )strchr(domainname+slashpos, '/'); |
57 | | - domainname[slashpos] = '\0'; // replace the slash with a nullbyte to cut the url |
58 | | - char * copyurl = strdup(newurl); |
59 | | - sprintf(newurl, "%s%s", domainname, copyurl); |
60 | | - free(copyurl); |
61 | | - free(domainname); |
62 | | - } |
63 | | - url = newurl; // Change pointer to the url that we just learned |
64 | | - printf("Redirecting to url: %s\n", url); |
65 | | - ret = downloadToBuffer(newurl, buf, bufsize); |
66 | | - return ret; |
| 67 | + if (newurl[0] == '/') { //if the url starts with a slash, it's local |
| 68 | + int slashpos = 0; |
| 69 | + char * domainname = strdup(url); |
| 70 | + if (strncmp("http", domainname, 4) == 0) slashpos = 8; //if the url in the entry starts with http:// or https:// we need to skip that |
| 71 | + slashpos = strchr(domainname+slashpos, '/')-domainname; |
| 72 | + domainname[slashpos] = '\0'; // replace the slash with a nullbyte to cut the url |
| 73 | + char * copyurl = strdup(newurl); |
| 74 | + sprintf(newurl, "%s%s", domainname, copyurl); |
| 75 | + free(copyurl); |
| 76 | + free(domainname); |
67 | 77 | } |
68 | | - } while ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)); |
| 78 | + |
| 79 | + printf("Redirecting to url:\n%s\n", newurl); |
| 80 | + ret = setupContext(context, newurl, size); |
| 81 | + free(newurl); |
| 82 | + return ret; |
| 83 | + } |
69 | 84 |
|
70 | 85 | if (statuscode != 200) { |
71 | 86 | printf("Error: HTTP status code is not 200 OK.\nStatus code: %lu\n", statuscode); |
72 | | - httpcCloseContext(&context); |
73 | | - if (newurl != NULL) free(newurl); |
74 | | - return -2; |
| 87 | + httpcCloseContext(context); |
| 88 | + return DL_ERROR_STATUSCODE; |
75 | 89 | } |
76 | 90 |
|
77 | | - ret = httpcGetDownloadSizeState(&context, NULL, &contentsize); |
| 91 | + ret = httpcGetDownloadSizeState(context, NULL, size); |
78 | 92 | if (ret != 0) { |
79 | | - httpcCloseContext(&context); |
80 | | - if (newurl != NULL) free(newurl); |
| 93 | + printf("Error in:\nhttpcGetDownloadSizeState\n"); |
| 94 | + httpcCloseContext(context); |
81 | 95 | return ret; |
82 | 96 | } |
83 | 97 |
|
84 | | - // Start with a single page buffer |
85 | | - *buf = (u8 *)malloc(0x1000); |
86 | | - if (buf == NULL) { |
87 | | - httpcCloseContext(&context); |
88 | | - if (newurl != NULL) free(newurl); |
89 | | - return -1; |
90 | | - } |
91 | | - |
92 | | - do { |
93 | | - // This download loop resizes the buffer as data is read. |
94 | | - ret = httpcDownloadData(&context, *buf+size, 0x1000, &readsize); |
95 | | - size += readsize; |
96 | | - if (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING) { |
97 | | - |
98 | | - hidScanInput(); |
99 | | - |
100 | | - if (hidKeysDown() & KEY_B) { |
101 | | - if (newurl != NULL) free(newurl); |
102 | | - if (lastbuf != NULL) free(lastbuf); |
103 | | - if (buf != NULL) free(buf); |
104 | | - httpcCloseContext(&context); |
105 | | - return 7; |
106 | | - } |
107 | | - |
108 | | - lastbuf = *buf; // Save the old pointer, in case realloc() fails. |
109 | | - *buf = realloc(*buf, size + 0x1000); |
110 | | - if (buf == NULL) { |
111 | | - httpcCloseContext(&context); |
112 | | - free(lastbuf); |
113 | | - if (newurl != NULL) free(newurl); |
114 | | - return -1; |
115 | | - } |
116 | | - } |
117 | | - } while (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING); |
118 | | - |
119 | | - if(ret != 0) { |
120 | | - httpcCloseContext(&context); |
121 | | - if (newurl != NULL) free(newurl); |
122 | | - free(buf); |
123 | | - return -1; |
124 | | - } |
125 | | - |
126 | | - // Resize the buffer back down to our actual final size |
127 | | - lastbuf = *buf; |
128 | | - *buf = realloc(*buf, size); |
129 | | - if(buf == NULL) { // realloc() failed. |
130 | | - httpcCloseContext(&context); |
131 | | - free(lastbuf); |
132 | | - if(newurl != NULL) free(newurl); |
133 | | - return -1; |
134 | | - } |
135 | | - |
136 | | - *bufsize = contentsize; |
137 | | - httpcCloseContext(&context); |
138 | 98 | return 0; |
139 | 99 | } |
140 | 100 |
|
141 | 101 | Result downloadToFile(const char * url, const char * filepath) |
142 | 102 | { |
143 | | - |
144 | 103 | if (url == NULL) { |
145 | 104 | printf("Download cannot start, the URL in config.json is blank.\n"); |
146 | | - return -1; |
| 105 | + return DL_ERROR_CONFIG; |
147 | 106 | } |
148 | 107 |
|
149 | 108 | if (filepath == NULL) { |
150 | 109 | printf("Download cannot start, file path in config.json is blank.\n"); |
151 | | - return -1; |
| 110 | + return DL_ERROR_CONFIG; |
152 | 111 | } |
153 | 112 |
|
154 | 113 | printf("Downloading file from:\n%s\nto:\n%s\n", url, filepath); |
155 | 114 |
|
| 115 | + httpcContext context; |
156 | 116 | Result ret = 0; |
157 | | - u8 * buf = NULL; |
158 | | - u32 size = 0; |
| 117 | + u32 contentsize = 0, readsize = 0; |
159 | 118 |
|
160 | | - ret = downloadToBuffer(url, &buf, &size); |
| 119 | + ret = setupContext(&context, url, &contentsize); |
161 | 120 | if (ret != 0) return ret; |
162 | 121 |
|
163 | | - FILE *fptr = fopen(filepath, "wb"); |
164 | | - if (fptr == NULL) { |
165 | | - printf("Couldnt open file to write.\n"); |
166 | | - return -1; |
| 122 | + printf("Downloading %lu bytes...\n", contentsize); |
| 123 | + |
| 124 | + FILE * fh = fopen(filepath, "wb"); |
| 125 | + if (fh == NULL) { |
| 126 | + printf("Error: couldn't open file to write.\n"); |
| 127 | + return DL_ERROR_WRITEFILE; |
| 128 | + } |
| 129 | + |
| 130 | + u8 * buf = malloc(0x1000); |
| 131 | + if (buf == NULL) { |
| 132 | + httpcCloseContext(&context); |
| 133 | + return DL_ERROR_ALLOC; |
167 | 134 | } |
168 | | - fwrite(buf, 1, size, fptr); |
169 | | - fclose(fptr); |
| 135 | + |
| 136 | + u64 startTime = osGetTime(); |
| 137 | + do { |
| 138 | + ret = httpcDownloadData(&context, buf, 0x1000, &readsize); |
| 139 | + fwrite(buf, 1, readsize, fh); |
| 140 | + } while (ret == (Result)HTTPC_RESULTCODE_DOWNLOADPENDING); |
| 141 | + printf("Download took %llu milliseconds.\n", osGetTime()-startTime); |
| 142 | + |
170 | 143 | free(buf); |
| 144 | + fclose(fh); |
| 145 | + httpcCloseContext(&context); |
| 146 | + |
| 147 | + if (ret != 0) { |
| 148 | + printf("Error in:\nhttpcDownloadData\n"); |
| 149 | + return ret; |
| 150 | + } |
| 151 | + |
171 | 152 | return 0; |
172 | 153 | } |
0 commit comments