| | /* |
---|
| | * httphead - show http header of a website |
---|
| | */ |
---|
| | |
---|
| | /* |
---|
| | * Copyright (c) 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> |
---|
| | * All rights reserved. |
---|
| | * |
---|
| | * Redistribution and use in source and binary forms, with or without |
---|
| | * modification, are permitted provided that the following conditions |
---|
| | * are met: |
---|
| | * 1. Redistributions of source code must retain the above copyright |
---|
| | * notice, this list of conditions and the following disclaimer. |
---|
| | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| | * notice, this list of conditions and the following disclaimer in the |
---|
| | * documentation and/or other materials provided with the distribution. |
---|
| | * 3. The name of the author may not be used to endorse or promote products |
---|
| | * derived from this software without specific prior written permission. |
---|
| | * |
---|
| | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
| | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
| | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
| | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
| | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
| | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
| | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
| | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
| | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
| | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
| | */ |
---|
| | |
---|
| | #include <unistd.h> |
---|
| | #include <stdlib.h> |
---|
| | #include <netdb.h> |
---|
| | |
---|
| | #include <errno.h> |
---|
| | #include <string.h> |
---|
| | |
---|
| | #include "httphead.h" |
---|
| | |
---|
| | const char usagemsg[] = |
---|
| | "usage: httphead [-r] [-q] [-p port] [-s host-] [-d path] [-s host] URL\n" |
---|
| | "\n" |
---|
| | "options:\n" |
---|
| | " -p port use this port instead of 80\n" |
---|
| | " -s host use this host instead of the one specified in the URL\n" |
---|
| | " -d path use this path instead of the one specified in the URL\n" |
---|
| | " -r show sent request\n" |
---|
| | " -q show only the recieved status code\n" |
---|
| | " also: -v show version\n" |
---|
| | " -h display this help\n" |
---|
| | " -l display (BSD) license\n" |
---|
| | ; |
---|
| | |
---|
| | void usage ( ); |
---|
| | |
---|
| | void crlf ( int s ); |
---|
| | |
---|
| | char* gethost ( char* url ); |
---|
| | char* getpath ( char* url ); |
---|
| | char* getstatuscode ( char* response ); |
---|
| | |
---|
| | int main ( int argc, char* argv[] ) { |
---|
| | |
---|
| | int tmp; |
---|
| | char* hend = NULL; |
---|
| | char buff[HH_BUFFSIZE+1]; |
---|
| | |
---|
| | char* url = NULL; |
---|
| | |
---|
| | char* host = NULL; |
---|
| | char* path = NULL; |
---|
| | int port = 80; |
---|
| | |
---|
| | int showrequest = 0; |
---|
| | int statuscodeonly = 0; |
---|
| | char* statuscode = NULL; |
---|
| | |
---|
| | struct hostent *remote_hostent = NULL; |
---|
| | struct sockaddr_in *remote_host_addr = NULL; |
---|
| | |
---|
| | int sock; |
---|
| | |
---|
| | while ( (tmp = getopt(argc, argv, "qrd:s:p:hlv")) != -1 ) { |
---|
| | switch ( tmp ) { |
---|
| | case 'h': |
---|
| | usage(); |
---|
| | exit(0); |
---|
| | case 'l': |
---|
| | license(); |
---|
| | exit(0); |
---|
| | case 'v': |
---|
| | version(); |
---|
| | exit(0); |
---|
| | case 'p': |
---|
| | port = atoi(optarg); |
---|
| | break; |
---|
| | case 's': |
---|
| | host = optarg; |
---|
| | break; |
---|
| | case 'd': |
---|
| | path = optarg; |
---|
| | break; |
---|
| | case 'q': |
---|
| | statuscodeonly = 1; |
---|
| | break; |
---|
| | case 'r': |
---|
| | showrequest = 1; |
---|
| | break; |
---|
| | } |
---|
| | } |
---|
| | |
---|
| | if ( optind >= argc ) { |
---|
| | usage(); |
---|
| | exit(0); |
---|
| | } |
---|
| | |
---|
| | url = argv[optind]; |
---|
| | |
---|
| | if ( path == NULL ) { |
---|
| | path = getpath(url); |
---|
| | } |
---|
| | |
---|
| | if ( host == NULL ) { |
---|
| | host = gethost(url); |
---|
| | } |
---|
| | |
---|
| | remote_hostent = gethostbyname(host); |
---|
| | |
---|
| | if ( remote_hostent == NULL ) { |
---|
| | herror(NULL); |
---|
| | exit(-1); |
---|
| | } |
---|
| | |
---|
| | remote_host_addr = alloca(sizeof(struct sockaddr_in)); |
---|
| | remote_host_addr->sin_family = AF_INET; |
---|
| | remote_host_addr->sin_addr = *((struct in_addr*) remote_hostent->h_addr); |
---|
| | remote_host_addr->sin_port = port; |
---|
| | |
---|
| | if ( (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) { |
---|
| | showerror("socket"); |
---|
| | exit(-1); |
---|
| | } |
---|
| | |
---|
| | if ( connect(sock, (struct sockaddr*)remote_host_addr, sizeof(struct sockaddr_in)) == -1 ) { |
---|
| | showerror("connect"); |
---|
| | exit(-1); |
---|
| | } |
---|
| | |
---|
| | |
---|
| | /* main */ |
---|
| | |
---|
| | if ( showrequest ) { |
---|
| | write(1, "GET ", 4); |
---|
| | write(1, path, strlen(path)); |
---|
| | write(1, " HTTP/1.0", 9); |
---|
| | crlf(1); |
---|
| | write(1, "Host: ", 6); |
---|
| | write(1, host, strlen(host)); |
---|
| | |
---|
| | crlf(1); |
---|
| | crlf(1); |
---|
| | |
---|
| | write(1, "Response:\n\n", 12); |
---|
| | } |
---|
| | |
---|
| | write(sock, "GET ", 4); |
---|
| | write(sock, path, strlen(path)); |
---|
| | write(sock, " HTTP/1.0", 9); |
---|
| | crlf(sock); |
---|
| | write(sock, "Host: ", 6); |
---|
| | write(sock, host, strlen(host)); |
---|
| | |
---|
| | crlf(sock); |
---|
| | crlf(sock); |
---|
| | |
---|
| | while ( (tmp = recv(sock, buff, HH_BUFFSIZE, 0)) > 0 ) { |
---|
| | buff[tmp] = '\0'; |
---|
| | |
---|
| | if ( (hend = strstr(buff, "\x0D\x0A\x0D\x0A")) != NULL) { |
---|
| | tmp = hend-buff; |
---|
| | *hend = '\n'; |
---|
| | *(hend+1) = '\0'; |
---|
| | } |
---|
| | |
---|
| | if ( statuscodeonly ) { |
---|
| | if ( (statuscode = getstatuscode(buff)) != NULL ) { |
---|
| | write(1, statuscode, 3); |
---|
| | write(1, "\n", 1); |
---|
| | break; |
---|
| | } |
---|
| | } else { |
---|
| | write(1, buff, tmp); |
---|
| | } |
---|
| | |
---|
| | if ( hend != NULL ) { |
---|
| | break; |
---|
| | } |
---|
| | } |
---|
| | |
---|
| | if ( shutdown(sock, 2) == -1 ) { |
---|
| | showerror("shutdown"); |
---|
| | exit(-1); |
---|
| | } |
---|
| | |
---|
| | if ( close(sock) == -1 ) { |
---|
| | showerror("close"); |
---|
| | exit(-1); |
---|
| | } |
---|
| | |
---|
| | exit(0); |
---|
| | } |
---|
| | |
---|
| | char* _gethoststart ( char* url ) { |
---|
| | char* s = NULL; |
---|
| | |
---|
| | s = strstr(url, "http://"); |
---|
| | if ( s == NULL ) { |
---|
| | s = strstr(url, "https://"); |
---|
| | if ( s == NULL ) { |
---|
| | s = url; // assume that there is no http[s]:// prefix |
---|
| | } else { |
---|
| | s += 8; |
---|
| | } |
---|
| | } else { |
---|
| | s += 7; |
---|
| | } |
---|
| | |
---|
| | if ( s >= url + strlen(url) ) { |
---|
| | return url; |
---|
| | } |
---|
| | |
---|
| | return s; |
---|
| | } |
---|
| | |
---|
| | int _gethostlen ( char* s ) { |
---|
| | int e = 0; |
---|
| | |
---|
| | while ( *(s+e) != '/' && *(s+e) != '?' && *(s+e) != '\0' ) { |
---|
| | e++; |
---|
| | } |
---|
| | |
---|
| | return e; |
---|
| | } |
---|
| | |
---|
| | char* getstatuscode ( char* s ) { |
---|
| | char* htp = NULL; |
---|
| | |
---|
| | if ( (htp = strstr(s, "HTTP/")) != NULL ) { |
---|
| | while ( *htp != '\0' && *htp != ' ' ) { |
---|
| | htp++; |
---|
| | } |
---|
| | |
---|
| | while ( *htp == ' ' ) { |
---|
| | htp++; |
---|
| | } |
---|
| | |
---|
| | if ( *htp == '\0' ) { |
---|
| | htp = NULL; |
---|
| | } |
---|
| | } |
---|
| | |
---|
| | return htp; |
---|
| | } |
---|
| | |
---|
| | char* getpath ( char* url ) { |
---|
| | char* s = NULL; |
---|
| | int e; |
---|
| | |
---|
| | s = _gethoststart(url); |
---|
| | |
---|
| | e = _gethostlen(s); |
---|
| | |
---|
| | s += e; |
---|
| | |
---|
| | if ( s >= url+strlen(url) ) { |
---|
| | s = (char*)malloc(2*sizeof(char)); |
---|
| | *s = '/'; |
---|
| | *(s+1) = '\0'; |
---|
| | } |
---|
| | |
---|
| | return s; |
---|
| | } |
---|
| | |
---|
| | char* gethost ( char* url ) { |
---|
| | char* s = NULL; |
---|
| | char* r = NULL; |
---|
| | int e = 0; |
---|
| | |
---|
| | s = _gethoststart(url); |
---|
| | |
---|
| | e = _gethostlen(s); |
---|
| | |
---|
| | if ( e == 0 ) { |
---|
| | return NULL; |
---|
| | } |
---|
| | |
---|
| | r = (char*)malloc(sizeof(char)*(e+1)); |
---|
| | |
---|
| | memcpy(r, s, e); |
---|
| | |
---|
| | r[e+1] = '\0'; |
---|
| | |
---|
| | return r; |
---|
| | } |
---|
| | |
---|
| | void crlf ( int s ) { |
---|
| | write(s, "\x0D\x0A", 2); |
---|
| | } |
---|
| | |
---|
| | void usage ( ) { |
---|
| | write(1, usagemsg, strlen(usagemsg)); |
---|
| | } |
---|
| | |
---|
| | |