2828#include <sys/stat.h>
2929#include <fcntl.h>
3030#include <ctype.h>
31+ #include <unistd.h>
3132
3233void usage (char * progname ) {
3334 dprintf (STDERR_FILENO ,
3435 "Usage: %s [options]... <URL>\n"
35- "\t-o , --outfile <FILE>\tOutput to file. Ignores -n,-h,-H,-s \n"
36- "\t-c , --cacert <FILE>\tRead Certificate Authorities certificates file, turns on certificate validation \n"
36+ "\t-C , --cacert <FILE>\tRead Certificate Authorities certificates file, turns on certificate validation \n"
37+ "\t-o , --outfile <FILE>\tOutput to file. Below options are ignored \n"
3738 "\t-h, --headers\t\tPrint headers too\n"
3839 "\t-H, -hh, --headers-only\tPrint headers only\n"
3940 "\t-s, --silent\t\tSilent mode. Print nothing\n"
40- "\t-n, --nreqs\t\tNumber of request\n" , progname );
41+ "\t-n, --nreqs\t\tNumber of request\n"
42+ "\t-c, --concurrency\tNuber of concurrent requests\n"
43+ "\t-r, --reconnect\t\tRequest non-persistent\n"
44+ "\t-f, --filedes\t\tFile descritor for data output (default: 1)\n"
45+ "Debugging options:\n"
46+ "\t-p, \t\t\tUse the 'content' pointer instead of vmbuf_write\n"
47+ , progname );
48+
4149 exit (EXIT_FAILURE );
4250}
4351
4452int main (int argc , char * argv []) {
4553
4654 static struct option long_options [] = {
4755 {"outfile" , 1 , 0 , 'o' },
48- {"cacert" , 1 , 0 , 'c ' },
56+ {"cacert" , 1 , 0 , 'C ' },
4957 {"headers" , 0 , 0 , 'h' },
5058 {"nreqs" , 1 , 0 , 'n' },
5159 {"silent" , 0 , 0 , 's' },
5260 {"headers-only" , 0 , 0 , 'H' },
61+ {"reconnect" , 0 , 0 , 'r' },
62+ {"concurrency" , 1 , 0 , 'c' },
63+ {"filedes" , 1 , 0 , 'f' },
5364 {0 , 0 , 0 , 0 }
5465 };
5566
56- int silent = 0 ;
67+ int concurrency = 1 ;
68+ char silent = 0 ;
5769 int64_t nreqs = 0 ;
58- int headers = 0 ;
70+ char headers = 0 ;
5971 char * cacert = NULL ;
60- char * file = NULL ;
72+ char * save_to_file = NULL ;
73+ char force_close = 0 ;
74+ char use_content = 0 ;
75+ int output_fileno = STDOUT_FILENO ;
6176
6277 for (;;) {
6378 int option_index = 0 ;
64- int c = getopt_long (argc , argv , "o:c:hn:sH " , long_options , & option_index );
79+ int c = getopt_long (argc , argv , "o:c:n:C:f:shHrp " , long_options , & option_index );
6580 if (c == -1 )
6681 break ;
6782 switch (c ) {
6883 case 'o' :
69- file = optarg ;
84+ save_to_file = optarg ;
7085 break ;
71- case 'c ' :
86+ case 'C ' :
7287 cacert = optarg ;
7388 break ;
7489 case 'h' :
7590 ++ headers ;
7691 break ;
7792 case 'n' :
78- nreqs = atoi (optarg );
93+ nreqs = strtoull (optarg , NULL , 10 );
7994 break ;
8095 case 's' :
8196 silent = 1 ;
8297 break ;
8398 case 'H' :
8499 headers += 2 ;
85100 break ;
101+ case 'r' :
102+ force_close = 1 ;
103+ break ;
104+ case 'c' :
105+ concurrency = atoi (optarg );
106+ break ;
107+ case 'p' :
108+ use_content = 1 ;
109+ break ;
110+ case 'f' :
111+ output_fileno = atoi (optarg );
112+ break ;
86113 default :
87114 LOGGER_ERROR ("Wrong argument:-%c" , c );
88115 usage (argv [0 ]);
@@ -100,7 +127,7 @@ int main(int argc, char *argv[]) {
100127
101128 if (nreqs < 1 ) nreqs = 1 ;
102129
103- if (file ) {
130+ if (save_to_file ) {
104131 if (nreqs > 1 )
105132 LOGGER_INFO ("File mode, nreqs will be ignored" );
106133 if (silent )
@@ -125,14 +152,14 @@ int main(int argc, char *argv[]) {
125152 if (!strncasecmp ("http://" , url , 7 )) {
126153 url += 7 ;
127154 } else if (!strncasecmp ("https://" , url , 8 )) {
128- if (http_client_pool_init_ssl (& client_pool , 1 , 1 , cacert ))
155+ if (http_client_pool_init_ssl (& client_pool , concurrency , 1 , cacert ))
129156 exit (EXIT_FAILURE );
130157 url += 8 ;
131158 port = 443 ;
132159 }
133160
134161 if (80 == port )
135- if (http_client_pool_init (& client_pool , 1 , 1 ))
162+ if (http_client_pool_init (& client_pool , concurrency , 1 ))
136163 exit (EXIT_FAILURE );
137164
138165 char * hostandport = strtok (url , "/" );
@@ -155,12 +182,12 @@ int main(int argc, char *argv[]) {
155182 LOGGER_ERROR ("Could not resolve: %s" , host );
156183 exit (EXIT_FAILURE );
157184 }
158- struct in_addr addr ;
159- addr = * (struct in_addr * )h -> h_addr_list [0 ];
160185
161- if (file ) {
186+ struct in_addr addr = * (struct in_addr * )h -> h_addr_list [0 ];
187+
188+ if (save_to_file ) {
162189 struct vmfile infile = VMFILE_INITIALIZER ;
163- if (0 != vmfile_init (& infile , file , 4096 )) {
190+ if (0 != vmfile_init (& infile , save_to_file , 4096 )) {
164191 LOGGER_PERROR ("Error opening file for write" );
165192 exit (EXIT_FAILURE );
166193 }
@@ -173,47 +200,65 @@ int main(int argc, char *argv[]) {
173200 vmfile_close (& infile );
174201
175202 } else {
176- struct http_client_context * rcctx ;
177- LOOP :
178- rcctx = http_client_pool_create_client2 (& client_pool , addr , port , host , NULL );
179- if (NULL == rcctx ) {
180- LOGGER_PERROR ("Error sending request" );
181- exit (EXIT_FAILURE );
182- }
183- vmbuf_sprintf (& rcctx -> request , "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n" , uri , host );
184- int persistent = 0 ;
185- for (; nreqs > 0 ; -- nreqs ) {
186- if (0 > http_client_send_request (rcctx )) {
187- if (!persistent ) -- nreqs ;
188- http_client_free (rcctx );
189- goto LOOP ;
203+ void requestor (void ) {
204+ struct http_client_context * rcctx ;
205+ LOOP :
206+ rcctx = http_client_pool_create_client2 (& client_pool , addr , port , host , NULL );
207+ if (NULL == rcctx ) {
208+ LOGGER_PERROR ("Error sending request" );
209+ exit (EXIT_FAILURE );
190210 }
191- /* Try to read right away, without epoll_wait */
192- ribs_swapcurcontext (RIBS_RESERVED_TO_CONTEXT (rcctx ));
193- //yield();
194- /* rcctx = http_client_get_last_context(); */
195- if (!silent ) {
196- if (headers > 1 )
197- vmbuf_wlocset (& rcctx -> response , vmbuf_rlocpos (& rcctx -> response )- 4 );
198- if (headers )
199- vmbuf_rlocset (& rcctx -> response , 0 );
200- vmbuf_write (& rcctx -> response , STDOUT_FILENO );
201- printf ("\n" );
202- }
203- /* Not persistent? */
204- if (!rcctx -> persistent ) {
211+ rcctx -> persistent = 1 ;
212+ vmbuf_sprintf (& rcctx -> request , "GET /%s HTTP/1.1\r\nHost: %s\r\n" , uri , host );
213+ if (force_close )
214+ vmbuf_strcpy (& rcctx -> request , "Connection: close\r\n\r\n" );
215+ else
216+ vmbuf_strcpy (& rcctx -> request , "\r\n" );
217+ while (nreqs > 0 ) {
205218 -- nreqs ;
206- http_client_free (rcctx );
207- goto LOOP ;
219+ /* attempt to write and read right away, without epoll_wait */
220+ ribs_swapcurcontext (RIBS_RESERVED_TO_CONTEXT (rcctx ));
221+ if (!silent ) {
222+ if (headers > 1 )
223+ vmbuf_wlocset (& rcctx -> response , vmbuf_rlocpos (& rcctx -> response )- 4 );
224+ if (headers )
225+ vmbuf_rlocset (& rcctx -> response , 0 );
226+ if (STDOUT_FILENO == output_fileno )
227+ vmbuf_chrcpy (& rcctx -> response , '\n' );
228+ if (use_content && rcctx -> content ) {
229+ vmbuf_chrcpy (& rcctx -> response , '\0' );
230+ dprintf (output_fileno , "%s" , rcctx -> content );
231+ } else
232+ vmbuf_write (& rcctx -> response , output_fileno );
233+ }
234+ /* Not persistent? */
235+ if (!rcctx -> persistent ) {
236+ http_client_free (rcctx );
237+ goto LOOP ;
238+ }
239+ /* clear the response buffer */
240+ vmbuf_reset (& rcctx -> response );
241+ /* rollback and reuse the request */
242+ vmbuf_rreset (& rcctx -> request );
243+ /* reset the fiber */
244+ http_client_reuse_context (rcctx );
245+ }
246+ if (rcctx -> persistent ) {
247+ rcctx -> persistent = 0 ;
248+ ribs_close (rcctx -> fd );
208249 }
209- persistent = 1 ;
210- /* clear the response buffer */
211- vmbuf_reset (& rcctx -> response );
212- /* rollback and reuse the request */
213- vmbuf_rreset (& rcctx -> request );
214- /* reset the fiber */
215- http_client_reuse_context (rcctx );
216- }
250+ http_client_free (rcctx );
251+ }
252+
253+ int i ;
254+ for (i = 0 ; i < concurrency ; ++ i ) {
255+ struct ribs_context * ctx = ribs_context_create (1024 * 1024 , 0 , requestor );
256+ queue_current_ctx ();
257+ ribs_swapcurcontext (ctx );
258+ }
259+ for (i = 0 ; i < concurrency ; ++ i ) {
260+ yield ();
261+ }
217262 }
218263 return 0 ;
219264}
0 commit comments