/* * 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)); }