]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/client.cc
3 * $Id: client.cc,v 1.109 2005/05/26 09:44:30 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.
43 static int client_comm_bind(int, const char *);
45 static int client_comm_connect(int, const char *, u_short
, struct timeval
*);
46 static void usage(const char *progname
);
48 static int Now(struct timeval
*);
49 static SIGHDLR catchSignal
;
50 static SIGHDLR pipe_handler
;
51 static void set_our_signal(void);
53 static ssize_t
myread(int fd
, void *buf
, size_t len
);
54 static ssize_t
mywrite(int fd
, void *buf
, size_t len
);
57 static char *put_file
= NULL
;
59 static struct stat sb
;
64 usage(const char *progname
)
67 "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"
69 " -P file PUT request.\n"
70 " -a Do NOT include Accept: header.\n"
71 " -r Force cache to reload URL.\n"
72 " -s Silent. Do not print data to stdout.\n"
73 " -v Verbose. Print outgoing message to stderr.\n"
74 " -i IMS If-Modified-Since time (in Epoch seconds).\n"
75 " -h host Retrieve URL from cache on hostname. Default is localhost.\n"
76 " -l host Specify a local IP address to bind to. Default is none.\n"
77 " -p port Port number of cache. Default is %d.\n"
78 " -m method Request method, default is GET.\n"
79 " -t count Trace count cache-hops\n"
80 " -g count Ping mode, \"count\" iterations (0 to loop until interrupted).\n"
81 " -I interval Ping interval in seconds (default 1 second).\n"
82 " -H 'string' Extra headers to send. Use '\\n' for new lines.\n"
83 " -T timeout Timeout value (seconds) for read/write operations.\n"
84 " -u user Proxy authentication username\n"
85 " -w password Proxy authentication password\n"
86 " -U user WWW authentication username\n"
87 " -W password WWW authentication password\n",
88 progname
, CACHE_HTTP_PORT
);
92 static int interrupted
= 0;
94 main(int argc
, char *argv
[])
96 int conn
, c
, len
, bytesWritten
;
97 int port
, to_stdout
, reload
;
100 int opt_noaccept
= 0;
102 const char *hostname
, *localhost
;
103 char url
[BUFSIZ
], msg
[49152], buf
[BUFSIZ
];
104 char extra_hdrs
[32768];
105 const char *method
= "GET";
108 int max_forwards
= -1;
110 struct timeval tv1
, tv2
;
113 long ping_min
= 0, ping_max
= 0, ping_sum
= 0, ping_mean
= 0;
114 char *proxy_user
= NULL
;
115 char *proxy_password
= NULL
;
116 char *www_user
= NULL
;
117 char *www_password
= NULL
;
119 /* set the defaults */
120 hostname
= "localhost";
122 extra_hdrs
[0] = '\0';
123 port
= CACHE_HTTP_PORT
;
131 usage(argv
[0]); /* need URL */
132 } else if (argc
>= 2) {
133 strncpy(url
, argv
[argc
- 1], BUFSIZ
);
134 url
[BUFSIZ
- 1] = '\0';
139 while ((c
= getopt(argc
, argv
, "ah:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:?")) != -1)
146 case 'h': /* remote host */
153 case 'l': /* local host */
159 case 's': /* silent */
164 case 'k': /* backward compat */
169 case 'r': /* reload */
174 case 'p': /* port number */
175 sscanf(optarg
, "%d", &port
);
178 port
= CACHE_HTTP_PORT
; /* default */
183 put_file
= xstrdup(optarg
);
188 ims
= (time_t) atoi(optarg
);
193 method
= xstrdup(optarg
);
198 method
= xstrdup("TRACE");
200 max_forwards
= atoi(optarg
);
207 pcount
= atoi(optarg
);
214 if ((ping_int
= atoi(optarg
) * 1000) <= 0)
220 if (strlen(optarg
)) {
222 strncpy(extra_hdrs
, optarg
, sizeof(extra_hdrs
));
224 while ((t
= strstr(extra_hdrs
, "\\n")))
225 *t
= '\r', *(t
+ 1) = '\n';
231 io_timeout
= atoi(optarg
);
239 proxy_password
= optarg
;
247 www_password
= optarg
;
251 /* undocumented: may increase verb-level by giving more -v's */
255 case '?': /* usage */
266 WSAStartup(2, &wsaData
);
269 /* Build the HTTP request */
270 if (strncmp(url
, "mgr:", 4) == 0) {
271 char *t
= xstrdup(url
+ 4);
272 snprintf(url
, BUFSIZ
, "cache_object://%s/%s", hostname
, t
);
277 put_fd
= open(put_file
, O_RDONLY
);
281 fprintf(stderr
, "%s: can't open file (%s)\n", argv
[0],
287 setmode(put_fd
, O_BINARY
);
294 snprintf(msg
, BUFSIZ
, "%s %s HTTP/1.0\r\n", method
, url
);
297 snprintf(buf
, BUFSIZ
, "Pragma: no-cache\r\n");
302 snprintf(buf
, BUFSIZ
, "Content-length: %d\r\n", (int) sb
.st_size
);
306 if (opt_noaccept
== 0) {
307 snprintf(buf
, BUFSIZ
, "Accept: */*\r\n");
312 snprintf(buf
, BUFSIZ
, "If-Modified-Since: %s\r\n", mkrfc1123(ims
));
316 if (max_forwards
> -1) {
317 snprintf(buf
, BUFSIZ
, "Max-Forwards: %d\r\n", max_forwards
);
322 char *user
= proxy_user
;
323 char *password
= proxy_password
;
327 password
= getpass("Proxy password: ");
332 fprintf(stderr
, "ERROR: Proxy password missing\n");
336 snprintf(buf
, BUFSIZ
, "%s:%s", user
, password
);
337 snprintf(buf
, BUFSIZ
, "Proxy-Authorization: Basic %s\r\n", base64_encode(buf
));
342 char *user
= www_user
;
343 char *password
= www_password
;
347 password
= getpass("WWW password: ");
352 fprintf(stderr
, "ERROR: WWW password missing\n");
356 snprintf(buf
, BUFSIZ
, "%s:%s", user
, password
);
357 snprintf(buf
, BUFSIZ
, "Authorization: Basic %s\r\n", base64_encode(buf
));
363 snprintf(buf
, BUFSIZ
, "Proxy-Connection: keep-alive\r\n");
365 snprintf(buf
, BUFSIZ
, "Connection: keep-alive\r\n");
370 strcat(msg
, extra_hdrs
);
371 snprintf(buf
, BUFSIZ
, "\r\n");
375 fprintf(stderr
, "headers: '%s'\n", msg
);
380 struct sigaction sa
, osa
;
382 if (sigaction(SIGINT
, NULL
, &osa
) == 0 && osa
.sa_handler
== SIG_DFL
) {
383 sa
.sa_handler
= catchSignal
;
385 sigemptyset(&sa
.sa_mask
);
386 (void) sigaction(SIGINT
, &sa
, NULL
);
392 if ((osig
= signal(SIGINT
, catchSignal
)) != SIG_DFL
)
393 (void) signal(SIGINT
, osig
);
399 loops
= ping
? pcount
: 1;
401 for (i
= 0; loops
== 0 || i
< loops
; i
++) {
403 /* Connect to the server */
405 if ((conn
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
406 perror("client: socket");
410 if (localhost
&& client_comm_bind(conn
, localhost
) < 0) {
411 perror("client: bind");
415 if (client_comm_connect(conn
, hostname
, port
, ping
? &tv1
: NULL
) < 0) {
417 fprintf(stderr
, "client: ERROR: Cannot connect to %s:%d: Host unknown.\n", hostname
, port
);
420 snprintf(tbuf
, BUFSIZ
, "client: ERROR: Cannot connect to %s:%d",
428 /* Send the HTTP request */
430 bytesWritten
= send(conn
, (const void *) msg
, strlen(msg
), 0);
434 bytesWritten
= mywrite(conn
, msg
, strlen(msg
));
438 if (bytesWritten
< 0) {
439 perror("client: ERROR: write");
441 } else if ((unsigned) bytesWritten
!= strlen(msg
)) {
442 fprintf(stderr
, "client: ERROR: Cannot send request?: %s\n", msg
);
448 lseek(put_fd
, 0, SEEK_SET
);
451 while ((x
= read(put_fd
, buf
, sizeof(buf
))) > 0) {
452 x
= write(conn
, buf
, x
);
455 while ((x
= myread(put_fd
, buf
, sizeof(buf
))) > 0) {
456 x
= mywrite(conn
, buf
, x
);
466 fprintf(stderr
, "client: ERROR: Cannot send file.\n");
472 setmode(1, O_BINARY
);
474 while ((len
= recv(conn
, (void *) buf
, sizeof(buf
), 0)) > 0) {
477 while ((len
= myread(conn
, buf
, sizeof(buf
))) > 0) {
482 fwrite(buf
, len
, 1, stdout
);
490 (void) close(conn
); /* done with socket */
502 elapsed_msec
= tvSubMsec(tv1
, tv2
);
504 tmp
= localtime(&t2s
);
505 fprintf(stderr
, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s\n",
506 tmp
->tm_year
+ 1900, tmp
->tm_mon
+ 1, tmp
->tm_mday
,
507 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
, i
+ 1,
508 elapsed_msec
/ 1000, elapsed_msec
% 1000,
509 elapsed_msec
? (double) fsize
/ elapsed_msec
: -1.0);
511 if (i
== 0 || elapsed_msec
< ping_min
)
512 ping_min
= elapsed_msec
;
514 if (i
== 0 || elapsed_msec
> ping_max
)
515 ping_max
= elapsed_msec
;
517 ping_sum
+= elapsed_msec
;
519 /* Delay until next "ping_int" boundary */
520 if ((loops
== 0 || i
+ 1 < loops
) && elapsed_msec
< ping_int
) {
523 long msec_left
= ping_int
- elapsed_msec
;
525 tvs
.tv_sec
= msec_left
/ 1000;
526 tvs
.tv_usec
= (msec_left
% 1000) * 1000;
527 select(0, NULL
, NULL
, NULL
, &tvs
);
533 ping_mean
= ping_sum
/ i
;
534 fprintf(stderr
, "%d requests, round-trip (secs) min/avg/max = "
535 "%ld.%03ld/%ld.%03ld/%ld.%03ld\n", i
,
536 ping_min
/ 1000, ping_min
% 1000, ping_mean
/ 1000, ping_mean
% 1000,
537 ping_max
/ 1000, ping_max
% 1000);
546 client_comm_bind(int sock
, const char *local_host
) {
548 static const struct hostent
*hp
= NULL
;
550 static struct sockaddr_in from_addr
;
552 /* Set up the source socket address from which to send. */
555 from_addr
.sin_family
= AF_INET
;
557 if ((hp
= gethostbyname(local_host
)) == 0) {
561 xmemcpy(&from_addr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
562 from_addr
.sin_port
= 0;
565 return bind(sock
, (struct sockaddr
*) &from_addr
, sizeof(struct sockaddr_in
));
570 client_comm_connect(int sock
, const char *dest_host
, u_short dest_port
, struct timeval
*tvp
) {
572 static const struct hostent
*hp
= NULL
;
574 static struct sockaddr_in to_addr
;
576 /* Set up the destination socket address for message to send to. */
580 to_addr
.sin_family
= AF_INET
;
582 if ((hp
= gethostbyname(dest_host
)) == 0) {
586 xmemcpy(&to_addr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
587 to_addr
.sin_port
= htons(dest_port
);
593 return connect(sock
, (struct sockaddr
*) &to_addr
, sizeof(struct sockaddr_in
));
598 Now(struct timeval
*tp
) {
599 #if GETTIMEOFDAY_NO_TZP
600 return gettimeofday(tp
);
603 return gettimeofday(tp
, NULL
);
608 catchSignal(int sig
) {
610 fprintf(stderr
, "Interrupted.\n");
614 pipe_handler(int sig
) {
615 fprintf(stderr
, "SIGPIPE received.\n");
619 set_our_signal(void) {
623 sa
.sa_handler
= pipe_handler
;
624 sa
.sa_flags
= SA_RESTART
;
625 sigemptyset(&sa
.sa_mask
);
627 if (sigaction(SIGPIPE
, &sa
, NULL
) < 0) {
628 fprintf(stderr
, "Cannot set PIPE signal.\n");
633 signal(SIGPIPE
, pipe_handler
);
639 #ifndef _SQUID_MSWIN_
641 myread(int fd
, void *buf
, size_t len
) {
643 return read(fd
, buf
, len
);
647 mywrite(int fd
, void *buf
, size_t len
) {
649 return write(fd
, buf
, len
);