]>
git.ipfire.org Git - thirdparty/squid.git/blob - tools/squidclient.cc
3 * $Id: squidclient.cc,v 1.11 2008/02/26 21:49:46 amosjeffries Exp $
5 * DEBUG: section 0 WWW Client
6 * AUTHOR: Harvest Derived
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
39 /** \cond AUTODOCS-IGNORE */
40 using namespace Squid
;
54 #include <sys/types.h>
57 #include <sys/socket.h>
65 #if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_) /* protect NEXTSTEP */
66 #define _SQUID_NETDB_H_
82 #include <netinet/in.h>
89 #include "IPAddress.h"
95 #define MESSAGELEN 65536
98 #define HEADERLEN 65536
101 typedef void SIGHDLR(int sig
);
103 /* Local functions */
104 static int client_comm_bind(int, const IPAddress
&);
106 static int client_comm_connect(int, const IPAddress
&, struct timeval
*);
107 static void usage(const char *progname
);
109 static int Now(struct timeval
*);
110 static SIGHDLR catchSignal
;
111 static SIGHDLR pipe_handler
;
112 static void set_our_signal(void);
113 static ssize_t
myread(int fd
, void *buf
, size_t len
);
114 static ssize_t
mywrite(int fd
, void *buf
, size_t len
);
116 static char *put_file
= NULL
;
118 static struct stat sb
;
120 int io_timeout
= 120;
124 Win32SockCleanup(void)
129 #endif /* ifdef _SQUID_MSWIN_ */
132 usage(const char *progname
)
136 "Usage: %s [-arsv] [-i IMS] [-h remote host] [-l local host] [-p port] [-m method] [-t count] [-I ping-interval] [-H 'strings'] [-T timeout] url\n"
138 " -P file PUT request.\n"
139 " -a Do NOT include Accept: header.\n"
140 " -r Force cache to reload URL.\n"
141 " -s Silent. Do not print data to stdout.\n"
142 " -v Verbose. Print outgoing message to stderr.\n"
143 " -i IMS If-Modified-Since time (in Epoch seconds).\n"
144 " -h host Retrieve URL from cache on hostname. Default is localhost.\n"
145 " -l host Specify a local IP address to bind to. Default is none.\n"
146 " -p port Port number of cache. Default is %d.\n"
147 " -m method Request method, default is GET.\n"
148 " -t count Trace count cache-hops\n"
149 " -g count Ping mode, \"count\" iterations (0 to loop until interrupted).\n"
150 " -I interval Ping interval in seconds (default 1 second).\n"
151 " -H 'string' Extra headers to send. Use '\\n' for new lines.\n"
152 " -T timeout Timeout value (seconds) for read/write operations.\n"
153 " -u user Proxy authentication username\n"
154 " -w password Proxy authentication password\n"
155 " -U user WWW authentication username\n"
156 " -W password WWW authentication password\n",
157 VERSION
, progname
, CACHE_HTTP_PORT
);
161 static int interrupted
= 0;
163 main(int argc
, char *argv
[])
165 int conn
, c
, len
, bytesWritten
;
166 int port
, to_stdout
, reload
;
169 int opt_noaccept
= 0;
171 const char *hostname
, *localhost
;
173 char url
[BUFSIZ
], msg
[MESSAGELEN
], buf
[BUFSIZ
];
174 char extra_hdrs
[HEADERLEN
];
175 const char *method
= "GET";
178 int max_forwards
= -1;
180 struct timeval tv1
, tv2
;
183 long ping_min
= 0, ping_max
= 0, ping_sum
= 0, ping_mean
= 0;
184 char *proxy_user
= NULL
;
185 char *proxy_password
= NULL
;
186 char *www_user
= NULL
;
187 char *www_password
= NULL
;
189 /* set the defaults */
190 hostname
= "localhost";
192 extra_hdrs
[0] = '\0';
193 port
= CACHE_HTTP_PORT
;
201 usage(argv
[0]); /* need URL */
202 } else if (argc
>= 2) {
203 strncpy(url
, argv
[argc
- 1], BUFSIZ
);
204 url
[BUFSIZ
- 1] = '\0';
209 while ((c
= getopt(argc
, argv
, "ah:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:?")) != -1)
216 case 'h': /* remote host */
223 case 'l': /* local host */
229 case 's': /* silent */
234 case 'k': /* backward compat */
239 case 'r': /* reload */
244 case 'p': /* port number */
245 sscanf(optarg
, "%d", &port
);
248 port
= CACHE_HTTP_PORT
; /* default */
253 put_file
= xstrdup(optarg
);
258 ims
= (time_t) atoi(optarg
);
263 method
= xstrdup(optarg
);
268 method
= xstrdup("TRACE");
270 max_forwards
= atoi(optarg
);
277 pcount
= atoi(optarg
);
284 if ((ping_int
= atoi(optarg
) * 1000) <= 0)
290 if (strlen(optarg
)) {
292 strncpy(extra_hdrs
, optarg
, sizeof(extra_hdrs
));
294 while ((t
= strstr(extra_hdrs
, "\\n")))
295 *t
= '\r', *(t
+ 1) = '\n';
300 io_timeout
= atoi(optarg
);
308 proxy_password
= optarg
;
316 www_password
= optarg
;
320 /* undocumented: may increase verb-level by giving more -v's */
324 case '?': /* usage */
334 WSAStartup(2, &wsaData
);
335 atexit(Win32SockCleanup
);
338 /* Build the HTTP request */
339 if (strncmp(url
, "mgr:", 4) == 0) {
340 char *t
= xstrdup(url
+ 4);
341 snprintf(url
, BUFSIZ
, "cache_object://%s/%s", hostname
, t
);
345 put_fd
= open(put_file
, O_RDONLY
);
349 fprintf(stderr
, "%s: can't open file (%s)\n", argv
[0],
354 setmode(put_fd
, O_BINARY
);
360 snprintf(msg
, BUFSIZ
, "%s %s HTTP/1.0\r\n", method
, url
);
363 snprintf(buf
, BUFSIZ
, "Pragma: no-cache\r\n");
367 snprintf(buf
, BUFSIZ
, "Content-length: %d\r\n", (int) sb
.st_size
);
370 if (opt_noaccept
== 0) {
371 snprintf(buf
, BUFSIZ
, "Accept: */*\r\n");
375 snprintf(buf
, BUFSIZ
, "If-Modified-Since: %s\r\n", mkrfc1123(ims
));
378 if (max_forwards
> -1) {
379 snprintf(buf
, BUFSIZ
, "Max-Forwards: %d\r\n", max_forwards
);
383 char *user
= proxy_user
;
384 char *password
= proxy_password
;
388 password
= getpass("Proxy password: ");
393 fprintf(stderr
, "ERROR: Proxy password missing\n");
396 snprintf(buf
, BUFSIZ
, "%s:%s", user
, password
);
397 snprintf(buf
, BUFSIZ
, "Proxy-Authorization: Basic %s\r\n", base64_encode(buf
));
401 char *user
= www_user
;
402 char *password
= www_password
;
406 password
= getpass("WWW password: ");
411 fprintf(stderr
, "ERROR: WWW password missing\n");
414 snprintf(buf
, BUFSIZ
, "%s:%s", user
, password
);
415 snprintf(buf
, BUFSIZ
, "Authorization: Basic %s\r\n", base64_encode(buf
));
420 snprintf(buf
, BUFSIZ
, "Proxy-Connection: keep-alive\r\n");
422 snprintf(buf
, BUFSIZ
, "Connection: keep-alive\r\n");
426 strcat(msg
, extra_hdrs
);
427 snprintf(buf
, BUFSIZ
, "\r\n");
431 fprintf(stderr
, "headers: '%s'\n", msg
);
436 struct sigaction sa
, osa
;
438 if (sigaction(SIGINT
, NULL
, &osa
) == 0 && osa
.sa_handler
== SIG_DFL
) {
439 sa
.sa_handler
= catchSignal
;
441 sigemptyset(&sa
.sa_mask
);
442 (void) sigaction(SIGINT
, &sa
, NULL
);
447 if ((osig
= signal(SIGINT
, catchSignal
)) != SIG_DFL
)
448 (void) signal(SIGINT
, osig
);
453 loops
= ping
? pcount
: 1;
455 for (i
= 0; loops
== 0 || i
< loops
; i
++) {
457 struct addrinfo
*AI
= NULL
;
459 /* Connect to the server */
462 if ( !iaddr
.GetHostByName(localhost
) ) {
463 fprintf(stderr
, "client: ERROR: Cannot resolve %s: Host unknown.\n", localhost
);
467 /* Process the remote host name to locate the Protocol required
468 in case we are being asked to link to another version of squid */
469 if ( !iaddr
.GetHostByName(hostname
) ) {
470 fprintf(stderr
, "client: ERROR: Cannot resolve %s: Host unknown.\n", hostname
);
475 iaddr
.GetAddrInfo(AI
);
476 if ((conn
= socket(AI
->ai_family
, AI
->ai_socktype
, 0)) < 0) {
477 perror("client: socket");
478 iaddr
.FreeAddrInfo(AI
);
481 iaddr
.FreeAddrInfo(AI
);
483 if (localhost
&& client_comm_bind(conn
, iaddr
) < 0) {
484 perror("client: bind");
489 if ( !iaddr
.GetHostByName(hostname
) ) {
490 fprintf(stderr
, "client: ERROR: Cannot resolve %s: Host unknown.\n", hostname
);
496 if (client_comm_connect(conn
, iaddr
, ping
? &tv1
: NULL
) < 0) {
497 char buf
[MAX_IPSTRLEN
];
498 iaddr
.ToURL(buf
, MAX_IPSTRLEN
);
500 fprintf(stderr
, "client: ERROR: Cannot connect to %s: Host unknown.\n", buf
);
503 snprintf(tbuf
, BUFSIZ
, "client: ERROR: Cannot connect to %s", buf
);
509 /* Send the HTTP request */
510 bytesWritten
= mywrite(conn
, msg
, strlen(msg
));
512 if (bytesWritten
< 0) {
513 perror("client: ERROR: write");
515 } else if ((unsigned) bytesWritten
!= strlen(msg
)) {
516 fprintf(stderr
, "client: ERROR: Cannot send request?: %s\n", msg
);
522 lseek(put_fd
, 0, SEEK_SET
);
525 while ((x
= read(put_fd
, buf
, sizeof(buf
))) > 0) {
528 while ((x
= myread(put_fd
, buf
, sizeof(buf
))) > 0) {
530 x
= mywrite(conn
, buf
, x
);
539 fprintf(stderr
, "client: ERROR: Cannot send file.\n");
544 setmode(1, O_BINARY
);
548 while ((len
= myread(conn
, buf
, sizeof(buf
))) > 0) {
552 fwrite(buf
, len
, 1, stdout
);
560 (void) close(conn
); /* done with socket */
572 elapsed_msec
= tvSubMsec(tv1
, tv2
);
574 tmp
= localtime(&t2s
);
575 fprintf(stderr
, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s\n",
576 tmp
->tm_year
+ 1900, tmp
->tm_mon
+ 1, tmp
->tm_mday
,
577 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
, i
+ 1,
578 elapsed_msec
/ 1000, elapsed_msec
% 1000,
579 elapsed_msec
? (double) fsize
/ elapsed_msec
: -1.0);
581 if (i
== 0 || elapsed_msec
< ping_min
)
582 ping_min
= elapsed_msec
;
584 if (i
== 0 || elapsed_msec
> ping_max
)
585 ping_max
= elapsed_msec
;
587 ping_sum
+= elapsed_msec
;
589 /* Delay until next "ping_int" boundary */
590 if ((loops
== 0 || i
+ 1 < loops
) && elapsed_msec
< ping_int
) {
593 long msec_left
= ping_int
- elapsed_msec
;
595 tvs
.tv_sec
= msec_left
/ 1000;
596 tvs
.tv_usec
= (msec_left
% 1000) * 1000;
597 select(0, NULL
, NULL
, NULL
, &tvs
);
603 ping_mean
= ping_sum
/ i
;
604 fprintf(stderr
, "%d requests, round-trip (secs) min/avg/max = "
605 "%ld.%03ld/%ld.%03ld/%ld.%03ld\n", i
,
606 ping_min
/ 1000, ping_min
% 1000, ping_mean
/ 1000, ping_mean
% 1000,
607 ping_max
/ 1000, ping_max
% 1000);
615 client_comm_bind(int sock
, const IPAddress
&addr
) {
619 static struct addrinfo
*AI
= NULL
;
621 /* Set up the source socket address from which to send. */
623 addr
.GetAddrInfo(AI
);
625 res
= bind(sock
, AI
->ai_addr
, AI
->ai_addrlen
);
627 addr
.FreeAddrInfo(AI
);
633 client_comm_connect(int sock
, const IPAddress
&addr
, struct timeval
*tvp
) {
635 static struct addrinfo
*AI
= NULL
;
637 /* Set up the destination socket address for message to send to. */
639 addr
.GetAddrInfo(AI
);
641 res
= connect(sock
, AI
->ai_addr
, AI
->ai_addrlen
);
643 addr
.FreeAddrInfo(AI
);
652 Now(struct timeval
*tp
) {
653 #if GETTIMEOFDAY_NO_TZP
654 return gettimeofday(tp
);
657 return gettimeofday(tp
, NULL
);
662 catchSignal(int sig
) {
664 fprintf(stderr
, "Interrupted.\n");
668 pipe_handler(int sig
) {
669 fprintf(stderr
, "SIGPIPE received.\n");
673 set_our_signal(void) {
677 sa
.sa_handler
= pipe_handler
;
678 sa
.sa_flags
= SA_RESTART
;
679 sigemptyset(&sa
.sa_mask
);
681 if (sigaction(SIGPIPE
, &sa
, NULL
) < 0) {
682 fprintf(stderr
, "Cannot set PIPE signal.\n");
686 signal(SIGPIPE
, pipe_handler
);
693 myread(int fd
, void *buf
, size_t len
) {
694 #ifndef _SQUID_MSWIN_
696 return read(fd
, buf
, len
);
699 return recv(fd
, buf
, len
, 0);
704 mywrite(int fd
, void *buf
, size_t len
) {
705 #ifndef _SQUID_MSWIN_
707 return write(fd
, buf
, len
);
710 return send(fd
, buf
, len
, 0);