]>
git.ipfire.org Git - thirdparty/squid.git/blob - tools/squidclient.cc
3 * $Id: squidclient.cc,v 1.1 2006/05/11 01:36:57 hno 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.
40 #include <sys/types.h>
41 #include <sys/socket.h>
56 typedef void SIGHDLR(int sig
);
59 static int client_comm_bind(int, const char *);
61 static int client_comm_connect(int, const char *, u_short
, struct timeval
*);
62 static void usage(const char *progname
);
64 static int Now(struct timeval
*);
65 static SIGHDLR catchSignal
;
66 static SIGHDLR pipe_handler
;
67 static void set_our_signal(void);
69 static ssize_t
myread(int fd
, void *buf
, size_t len
);
70 static ssize_t
mywrite(int fd
, void *buf
, size_t len
);
73 static char *put_file
= NULL
;
75 static struct stat sb
;
80 usage(const char *progname
)
83 "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"
85 " -P file PUT request.\n"
86 " -a Do NOT include Accept: header.\n"
87 " -r Force cache to reload URL.\n"
88 " -s Silent. Do not print data to stdout.\n"
89 " -v Verbose. Print outgoing message to stderr.\n"
90 " -i IMS If-Modified-Since time (in Epoch seconds).\n"
91 " -h host Retrieve URL from cache on hostname. Default is localhost.\n"
92 " -l host Specify a local IP address to bind to. Default is none.\n"
93 " -p port Port number of cache. Default is %d.\n"
94 " -m method Request method, default is GET.\n"
95 " -t count Trace count cache-hops\n"
96 " -g count Ping mode, \"count\" iterations (0 to loop until interrupted).\n"
97 " -I interval Ping interval in seconds (default 1 second).\n"
98 " -H 'string' Extra headers to send. Use '\\n' for new lines.\n"
99 " -T timeout Timeout value (seconds) for read/write operations.\n"
100 " -u user Proxy authentication username\n"
101 " -w password Proxy authentication password\n"
102 " -U user WWW authentication username\n"
103 " -W password WWW authentication password\n",
104 progname
, CACHE_HTTP_PORT
);
108 static int interrupted
= 0;
110 main(int argc
, char *argv
[])
112 int conn
, c
, len
, bytesWritten
;
113 int port
, to_stdout
, reload
;
116 int opt_noaccept
= 0;
118 const char *hostname
, *localhost
;
119 char url
[BUFSIZ
], msg
[49152], buf
[BUFSIZ
];
120 char extra_hdrs
[32768];
121 const char *method
= "GET";
124 int max_forwards
= -1;
126 struct timeval tv1
, tv2
;
129 long ping_min
= 0, ping_max
= 0, ping_sum
= 0, ping_mean
= 0;
130 char *proxy_user
= NULL
;
131 char *proxy_password
= NULL
;
132 char *www_user
= NULL
;
133 char *www_password
= NULL
;
135 /* set the defaults */
136 hostname
= "localhost";
138 extra_hdrs
[0] = '\0';
139 port
= CACHE_HTTP_PORT
;
147 usage(argv
[0]); /* need URL */
148 } else if (argc
>= 2) {
149 strncpy(url
, argv
[argc
- 1], BUFSIZ
);
150 url
[BUFSIZ
- 1] = '\0';
155 while ((c
= getopt(argc
, argv
, "ah:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:?")) != -1)
162 case 'h': /* remote host */
169 case 'l': /* local host */
175 case 's': /* silent */
180 case 'k': /* backward compat */
185 case 'r': /* reload */
190 case 'p': /* port number */
191 sscanf(optarg
, "%d", &port
);
194 port
= CACHE_HTTP_PORT
; /* default */
199 put_file
= xstrdup(optarg
);
204 ims
= (time_t) atoi(optarg
);
209 method
= xstrdup(optarg
);
214 method
= xstrdup("TRACE");
216 max_forwards
= atoi(optarg
);
223 pcount
= atoi(optarg
);
230 if ((ping_int
= atoi(optarg
) * 1000) <= 0)
236 if (strlen(optarg
)) {
238 strncpy(extra_hdrs
, optarg
, sizeof(extra_hdrs
));
240 while ((t
= strstr(extra_hdrs
, "\\n")))
241 *t
= '\r', *(t
+ 1) = '\n';
247 io_timeout
= atoi(optarg
);
255 proxy_password
= optarg
;
263 www_password
= optarg
;
267 /* undocumented: may increase verb-level by giving more -v's */
271 case '?': /* usage */
282 WSAStartup(2, &wsaData
);
285 /* Build the HTTP request */
286 if (strncmp(url
, "mgr:", 4) == 0) {
287 char *t
= xstrdup(url
+ 4);
288 snprintf(url
, BUFSIZ
, "cache_object://%s/%s", hostname
, t
);
293 put_fd
= open(put_file
, O_RDONLY
);
297 fprintf(stderr
, "%s: can't open file (%s)\n", argv
[0],
303 setmode(put_fd
, O_BINARY
);
310 snprintf(msg
, BUFSIZ
, "%s %s HTTP/1.0\r\n", method
, url
);
313 snprintf(buf
, BUFSIZ
, "Pragma: no-cache\r\n");
318 snprintf(buf
, BUFSIZ
, "Content-length: %d\r\n", (int) sb
.st_size
);
322 if (opt_noaccept
== 0) {
323 snprintf(buf
, BUFSIZ
, "Accept: */*\r\n");
328 snprintf(buf
, BUFSIZ
, "If-Modified-Since: %s\r\n", mkrfc1123(ims
));
332 if (max_forwards
> -1) {
333 snprintf(buf
, BUFSIZ
, "Max-Forwards: %d\r\n", max_forwards
);
338 char *user
= proxy_user
;
339 char *password
= proxy_password
;
343 password
= getpass("Proxy password: ");
348 fprintf(stderr
, "ERROR: Proxy password missing\n");
352 snprintf(buf
, BUFSIZ
, "%s:%s", user
, password
);
353 snprintf(buf
, BUFSIZ
, "Proxy-Authorization: Basic %s\r\n", base64_encode(buf
));
358 char *user
= www_user
;
359 char *password
= www_password
;
363 password
= getpass("WWW password: ");
368 fprintf(stderr
, "ERROR: WWW password missing\n");
372 snprintf(buf
, BUFSIZ
, "%s:%s", user
, password
);
373 snprintf(buf
, BUFSIZ
, "Authorization: Basic %s\r\n", base64_encode(buf
));
379 snprintf(buf
, BUFSIZ
, "Proxy-Connection: keep-alive\r\n");
381 snprintf(buf
, BUFSIZ
, "Connection: keep-alive\r\n");
386 strcat(msg
, extra_hdrs
);
387 snprintf(buf
, BUFSIZ
, "\r\n");
391 fprintf(stderr
, "headers: '%s'\n", msg
);
396 struct sigaction sa
, osa
;
398 if (sigaction(SIGINT
, NULL
, &osa
) == 0 && osa
.sa_handler
== SIG_DFL
) {
399 sa
.sa_handler
= catchSignal
;
401 sigemptyset(&sa
.sa_mask
);
402 (void) sigaction(SIGINT
, &sa
, NULL
);
408 if ((osig
= signal(SIGINT
, catchSignal
)) != SIG_DFL
)
409 (void) signal(SIGINT
, osig
);
415 loops
= ping
? pcount
: 1;
417 for (i
= 0; loops
== 0 || i
< loops
; i
++) {
419 /* Connect to the server */
421 if ((conn
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
422 perror("client: socket");
426 if (localhost
&& client_comm_bind(conn
, localhost
) < 0) {
427 perror("client: bind");
431 if (client_comm_connect(conn
, hostname
, port
, ping
? &tv1
: NULL
) < 0) {
433 fprintf(stderr
, "client: ERROR: Cannot connect to %s:%d: Host unknown.\n", hostname
, port
);
436 snprintf(tbuf
, BUFSIZ
, "client: ERROR: Cannot connect to %s:%d",
444 /* Send the HTTP request */
446 bytesWritten
= send(conn
, (const void *) msg
, strlen(msg
), 0);
450 bytesWritten
= mywrite(conn
, msg
, strlen(msg
));
454 if (bytesWritten
< 0) {
455 perror("client: ERROR: write");
457 } else if ((unsigned) bytesWritten
!= strlen(msg
)) {
458 fprintf(stderr
, "client: ERROR: Cannot send request?: %s\n", msg
);
464 lseek(put_fd
, 0, SEEK_SET
);
467 while ((x
= read(put_fd
, buf
, sizeof(buf
))) > 0) {
468 x
= write(conn
, buf
, x
);
471 while ((x
= myread(put_fd
, buf
, sizeof(buf
))) > 0) {
472 x
= mywrite(conn
, buf
, x
);
482 fprintf(stderr
, "client: ERROR: Cannot send file.\n");
488 setmode(1, O_BINARY
);
490 while ((len
= recv(conn
, (void *) buf
, sizeof(buf
), 0)) > 0) {
493 while ((len
= myread(conn
, buf
, sizeof(buf
))) > 0) {
498 fwrite(buf
, len
, 1, stdout
);
506 (void) close(conn
); /* done with socket */
518 elapsed_msec
= tvSubMsec(tv1
, tv2
);
520 tmp
= localtime(&t2s
);
521 fprintf(stderr
, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s\n",
522 tmp
->tm_year
+ 1900, tmp
->tm_mon
+ 1, tmp
->tm_mday
,
523 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
, i
+ 1,
524 elapsed_msec
/ 1000, elapsed_msec
% 1000,
525 elapsed_msec
? (double) fsize
/ elapsed_msec
: -1.0);
527 if (i
== 0 || elapsed_msec
< ping_min
)
528 ping_min
= elapsed_msec
;
530 if (i
== 0 || elapsed_msec
> ping_max
)
531 ping_max
= elapsed_msec
;
533 ping_sum
+= elapsed_msec
;
535 /* Delay until next "ping_int" boundary */
536 if ((loops
== 0 || i
+ 1 < loops
) && elapsed_msec
< ping_int
) {
539 long msec_left
= ping_int
- elapsed_msec
;
541 tvs
.tv_sec
= msec_left
/ 1000;
542 tvs
.tv_usec
= (msec_left
% 1000) * 1000;
543 select(0, NULL
, NULL
, NULL
, &tvs
);
549 ping_mean
= ping_sum
/ i
;
550 fprintf(stderr
, "%d requests, round-trip (secs) min/avg/max = "
551 "%ld.%03ld/%ld.%03ld/%ld.%03ld\n", i
,
552 ping_min
/ 1000, ping_min
% 1000, ping_mean
/ 1000, ping_mean
% 1000,
553 ping_max
/ 1000, ping_max
% 1000);
562 client_comm_bind(int sock
, const char *local_host
) {
564 static const struct hostent
*hp
= NULL
;
566 static struct sockaddr_in from_addr
;
568 /* Set up the source socket address from which to send. */
571 from_addr
.sin_family
= AF_INET
;
573 if ((hp
= gethostbyname(local_host
)) == 0) {
577 xmemcpy(&from_addr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
578 from_addr
.sin_port
= 0;
581 return bind(sock
, (struct sockaddr
*) &from_addr
, sizeof(struct sockaddr_in
));
586 client_comm_connect(int sock
, const char *dest_host
, u_short dest_port
, struct timeval
*tvp
) {
588 static const struct hostent
*hp
= NULL
;
590 static struct sockaddr_in to_addr
;
592 /* Set up the destination socket address for message to send to. */
596 to_addr
.sin_family
= AF_INET
;
598 if ((hp
= gethostbyname(dest_host
)) == 0) {
602 xmemcpy(&to_addr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
603 to_addr
.sin_port
= htons(dest_port
);
609 return connect(sock
, (struct sockaddr
*) &to_addr
, sizeof(struct sockaddr_in
));
614 Now(struct timeval
*tp
) {
615 #if GETTIMEOFDAY_NO_TZP
616 return gettimeofday(tp
);
619 return gettimeofday(tp
, NULL
);
624 catchSignal(int sig
) {
626 fprintf(stderr
, "Interrupted.\n");
630 pipe_handler(int sig
) {
631 fprintf(stderr
, "SIGPIPE received.\n");
635 set_our_signal(void) {
639 sa
.sa_handler
= pipe_handler
;
640 sa
.sa_flags
= SA_RESTART
;
641 sigemptyset(&sa
.sa_mask
);
643 if (sigaction(SIGPIPE
, &sa
, NULL
) < 0) {
644 fprintf(stderr
, "Cannot set PIPE signal.\n");
649 signal(SIGPIPE
, pipe_handler
);
655 #ifndef _SQUID_MSWIN_
657 myread(int fd
, void *buf
, size_t len
) {
659 return read(fd
, buf
, len
);
663 mywrite(int fd
, void *buf
, size_t len
) {
665 return write(fd
, buf
, len
);