2 * Acess2 Command-line HTTP Client (wget)
25 int main(int argc, char *argv[]);
26 int _ParseHeaderLine(char *Line, int State, size_t *Size);
27 void writef(int fd, const char *format, ...);
29 int main(int argc, char *argv[])
32 gasURLs = malloc( (argc - 1) * sizeof(*gasURLs) );
35 for(int i = 1; i < argc; i ++ )
40 gasURLs[giNumURLs++] = arg;
42 else if( arg[1] != '-') {
51 for( int i = 0; i < giNumURLs; i ++ )
54 tURI *uri = URI_Parse(gasURLs[i]);
55 struct addrinfo *addrinfo;
58 fprintf(stderr, "'%s' is not a valid URL", gasURLs[i]);
62 printf("Proto: %s, Host: %s, Path: %s\n", uri->Proto, uri->Host, uri->Path);
64 if( uri->Path[0] == '\0' || uri->Path[strlen(uri->Path)-1] == '/' )
65 outfile = "index.html";
67 outfile = strrchr(uri->Path, '/');
74 if( strcmp(uri->Proto, "http") == 0 ) {
77 else if( strcmp(uri->Proto, "https") == 0 ) {
82 fprintf(stderr, "Unknown protocol '%s'\n", uri->Proto);
87 rv = getaddrinfo(uri->Host, NULL, NULL, &addrinfo);
89 fprintf(stderr, "Unable to resolve %s: %s\n", uri->Host, gai_strerror(rv));
93 for( struct addrinfo *addr = addrinfo; addr != NULL; addr = addr->ai_next )
96 // TODO: Convert to POSIX/BSD
97 // NOTE: using addr->ai_addr will break for IPv6, as there is more info before the address
100 printf("Attempting [%s]:80\n", Net_PrintAddress(addr->ai_family, addr->ai_addr->sa_data));
102 sock = Net_OpenSocket_TCPC(addr->ai_family, addr->ai_addr->sa_data, 80);
107 _SysDebug("Connected as %i", sock);
109 writef(sock, "GET /%s HTTP/1.1\r\n", uri->Path);
110 writef(sock, "Host: %s\r\n", uri->Host);
111 // writef(sock, "Accept-Encodings: */*\r\n");
112 writef(sock, "User-Agent: awget/0.1 (Acess2)\r\n");
113 writef(sock, "\r\n");
116 char inbuf[BUFSIZ+1];
117 size_t offset = 0, len = 0;
119 size_t bytes_seen = 0;
120 size_t bytes_wanted = -1; // invalid
124 while( state == 0 || state == 1 )
126 if( offset == BUFSIZ ) {
132 char *eol = strchr(inbuf, '\n');
133 // No end of line char? read some more
135 // TODO: Handle -1 return
136 len += read(sock, inbuf + offset, BUFSIZ - 1 - offset);
140 // abuse offset as the end of the string
141 offset = (eol - inbuf) + 1;
146 if( eol - 1 >= inbuf )
150 state = _ParseHeaderLine(inbuf, state, &bytes_wanted);
152 // Move unused data down in memory
154 memmove( inbuf, inbuf + offset, BUFSIZ - offset );
160 _SysDebug("RXing %i bytes to '%s'", bytes_wanted, outfile);
161 int outfd = open(outfile, O_WR|O_CREAT, 0666);
163 fprintf(stderr, "Unable to open '%s' for writing\n", outfile);
167 // Write the remainder of the buffer
170 write(outfd, inbuf, len);
172 _SysDebug("%i/%i bytes done", bytes_seen, bytes_wanted);
173 } while( bytes_seen < bytes_wanted && (len = read(sock, inbuf, sizeof(inbuf))) > 0 );
178 _SysDebug("Closing socket");
189 int _ParseHeaderLine(char *Line, int State, size_t *Size)
191 _SysDebug("Header - %s", Line);
192 // First line (Status and version)
195 // HACK - assumes HTTP/1.1 (well, 9 chars before status)
196 switch( atoi(Line + 9) )
202 fprintf(stderr, "Unknown HTTP status - %s\n", Line + 9);
207 else if( Line[0] == '\0' )
215 char *colon = strchr(Line, ':');
216 if(colon == NULL) return 1;
220 if( strcmp(Line, "Content-Length") == 0 ) {
224 printf("Ignorning header '%s' = '%s'\n", Line, value);
231 void writef(int fd, const char *format, ...)
236 va_start(args, format);
237 len = vsnprintf(NULL, 0, format, args);
241 va_start(args, format);
242 vsnprintf(data, len+1, format, args);
245 write(fd, data, len);