source: project/wiki/eggref/4/http-client @ 36705

Last change on this file since 36705 was 36705, checked in by sjamaan, 8 months ago

Update http-client C4 changelog with 0.18

File size: 28.9 KB
Line 
1[[tags: egg]]
2
3== http-client
4
5[[toc:]]
6
7=== Description
8
9Http-client is a highlevel HTTP client library.
10
11=== Author
12
13[[/users/peter-bex|Peter Bex]]
14
15=== Requirements
16
17Requires the [[intarweb]], [[sendfile]], [[uri-common]] and [[simple-md5]] extensions.
18
19The [[openssl]] extension is optional as of 0.7; if it's not installed
20you'll get an error when trying to access a HTTPS URI.
21
22=== Documentation
23
24==== Main request procedures
25
26<procedure>(call-with-response request writer reader)</procedure>
27
28This is the core http-client procedure, but it is also pretty
29low-level.  It is only necessary to use this when you want the most
30control over the request/response cycle.  Otherwise, you should use
31{{with-input-from-request}}, {{call-with-input-request}} or
32{{call-with-input-request*}}.
33
34{{request}} is the request object that contains information about the
35request to perform.  {{reader}} is a procedure that receives the
36response object and should read the ''entire'' request body (any
37leftover data will cause errors on subsequent requests with keepalive
38connections), {{writer}} is a procedure that receives the request
39object and should write the request body.
40
41The {{writer}} should be prepared to be called several times; if the
42response is a redirect or some other status that indicates the server
43wants the client to perform a new request, the writer should be ready
44to write a request body for this new request. In case digest
45authentication with message integrity checking is used, {{writer}} is
46always invoked at least twice, once to determine the message digest of
47the response and once to actually write the response.
48
49Returns three values: The result of the call to {{reader}} (or {{#f}}
50if there is no message body in the response), the request-uri of
51the last request and the response object. The request-uri is useful
52because this is to be used as the base uri of the document. This can
53differ from the initial request in the presence of redirects.
54
55If there is no response body to read (as determined by intarweb's
56{{response-has-message-body-for-request?}}), the {{reader}} procedure
57is not invoked at all.
58
59If successive requests cause more than {{max-redirect-depth}} redirect
60responses to occur, a condition of type
61{{(exn http redirect-depth-exceeded)}} is raised.
62
63If the request's URI or the URI of a used proxy is of an unsupported
64type, a condition of type {{(exn http unsupported-uri-scheme)}} is
65raised (this can of course also occur when the initial URI is correct,
66but the server redirects to an URI with an unsupported scheme).
67
68When the request requires authentication of an unsupported type, a
69condition of type {{(exn http unknown-authtype)}} is raised.
70
71<procedure>(call-with-input-request uri-or-request writer reader)</procedure>
72
73This procedure is a convenience wrapper around {{call-with-response}}.
74
75It is much less strict - {{uri-or-request}} can be an [[intarweb]]
76request object, but also an [[uri-common]] object or even a string
77with the URI in it, in which case a request object will be
78automatically constructed around the URI, using the {{GET}} method
79when {{writer}} is {{#f}} or the {{POST}} method when {{writer}} is
80not {{#f}}.
81
82{{writer}} can be either {{#f}} (in which case nothing is written and
83the {{GET}} method chosen), a string containing the raw data to send,
84an alist, or a procedure that accepts a port and writes the
85response data to it.  If you supply a procedure, do not forget to set
86the {{content-length}} header!  In the other cases, whenever possible,
87the length is calculated and the header automatically set for you.
88
89If you supplied an alist, the {{content-type}} header is automatically
90set to {{application/x-www-form-urlencoded}} unless there's an alist
91entry whose value is a list starting with the keyword {{file:}}, in
92which case {{multipart/form-data}} is used.  See the examples for
93{{with-input-from-request}} below.  If the data cannot be form-encoded,
94a condition of type {{(exn http formdata-error)}} is raised.
95
96{{reader}} is either {{#f}} or a procedure which accepts a port and
97reads out the data.  If there is data left in the port when the reader
98returns (or {{#f}} was supplied), this will be automatically discarded
99to avoid problems.
100
101Returns three values: The result of the call to {{reader}} (or {{#f}}
102if there is no message body in the response), the request-uri of the
103last request and the response object.  If the response code is not in
104the 200 class, it will raise a condition of type
105{{(exn http client-error)}}, {{(exn http server-error)}} or
106{{(exn http unexpected-server-response)}}, depending on the response
107code.  This includes {{404 not found}} (which is a {{client-error}}).
108
109If there is no response body to read (as determined by intarweb's
110{{response-has-message-body-for-request?}}), the {{reader}} procedure
111is not invoked at all.
112
113When posting multipart form data, the value of a file entry is a list
114of keyword-value pairs.  The following keywords are recognised:
115
116; {{file:}} : This indicates the file to read from.  Can be either a string or a port. This ''must'' be specified, everything else is optional.
117; {{filename:}} : This indicates the filename to pass on to the server.  If not specified or {{#f}}, the {{file:}}'s string (or port-name in case of a port) will be used.
118; {{headers:}} : Additional headers to send for this entry (an [[intarweb]] headers-object).
119
120If the URI argument is not a valid URI, a condition of type
121{{(exn http client-error bad-uri)}} will be raised.
122
123If the writer is a list it is taken to be form-data, but if the
124encoding fails, a condition of type
125{{(exn http client-error form-data-error)}} will be raised.
126
127
128<procedure>(call-with-input-request* uri-or-request writer reader)</procedure>
129
130As {{call-with-input-request}}, except {{reader}} is passed two
131arguments: the input port and the complete intarweb response object
132(useful for when you want to inspect headers or other aspects of the
133response).
134
135Please note that the port is '''not''' the same as the
136{{response-port}} from the response object: the port is delimited so
137that you can read until {{EOF}}.  The {{response-port}} is the
138original underlying, unbounded port.  If you do want to read from it,
139you must make sure to read no more than what's in the
140{{Content-Length}} header, if present.  If the header is not present,
141it will either be a chunked port (which is implicitly delimited by
142intarweb) or the port will be closed by the remote end after it is
143consumed, so you can read until EOF in that case.
144
145<procedure>(with-input-from-request uri-or-request writer-thunk reader-thunk)</procedure>
146
147Same as {{call-with-input-request}}, except when you pass a procedure
148as {{reader-thunk}} or {{writer-thunk}} it has to be a thunk (lambda
149of no arguments) instead of a procedure of one argument.  These thunks
150will be executed with the current input (or output) port to the
151request or response port, respectively.
152
153You can still pass {{#f}} for both or an alist or string for
154{{writer-thunk}}.
155
156===== Examples
157
158<enscript highlight="scheme">
159(use http-client)
160
161;; Start with a simple GET request:
162(with-input-from-request "http://wiki.call-cc.org/" #f read-string)
163 => ;; [the chicken wiki page HTML contents]
164
165;; Perform a POST of the key "test" with value "value" to an echo service:
166(with-input-from-request "http://localhost/echo-service"
167                         '((test . "value")) read-string)
168 => "You posted: test=value"
169
170;; Performing a PUT request (a less commonly used method) requires
171;; constructing your request object manually:
172
173(use intarweb uri-common)  ; Required for "make-request" and "uri-reference"
174
175(with-input-from-request
176  (make-request method: 'PUT
177                uri: (uri-reference "http://example.com/blabla"))
178  (lambda () (print "Page contents"))
179  read-string)
180
181;; Performing a JSON PUT request furthermore requires you to
182;; pass custom headers:
183(let* ((uri (uri-reference "http://www.example.com/some/document"))
184       (req (make-request method: 'PUT
185                          uri: uri
186                          headers: (headers '((content-type application/json))))))
187  (with-input-from-request req "Contents of the document" read-string))
188
189;; Finally, an example where we need to send an "attachment" (file)
190;; We post a file to the echo-service from the first example.
191;; This results in a multi-part POST request, for which we set
192;; custom headers on the file (but not the main request)
193(with-input-from-request "http://localhost/echo-service"
194                         '((test . "value")
195                           (test-file file: "/tmp/myfile" filename: "hello.txt"
196                                      headers: ((content-type text/plain))))
197                         read-string)
198 => "You posted: test=value and a file named \"hello.txt\""
199</enscript>
200
201
202==== Request handling parameters
203
204<parameter>(max-retry-attempts [number])</parameter>
205
206When a request fails because of an I/O or network problem (or simply
207because the remote end closed a persistent connection while we were
208doing something else), the library will try to establish a new
209connection and perform the request again.  This parameter controls how
210many times this is allowed to be done.  If {{#f}}, it will never give up.
211
212Defaults to 1.
213
214<parameter>(retry-request? [predicate])</parameter>
215
216This procedure is invoked when a retry should take place, to determine
217if it should take place at all.  It should be a procedure accepting a
218request object and returning {{#f}} or a true value.  If the value is
219true, the new request will be sent.  Otherwise, the error that caused
220the retry attempt will be re-raised.
221
222Defaults to {{idempotent?}}, from [[intarweb]].  This is because
223non-idempotent requests cannot be safely retried when it is unknown
224whether the previous request reached the server or not.
225
226<parameter>(max-redirect-depth [number])</parameter>
227
228The maximum number of allowed redirects, or {{#f}} if there is no
229limit.  Currently there's no automatic redirect loop detection
230algorithm implemented.  If zero, no redirects will be followed at all.
231
232Defaults to 5.
233
234When the redirect limit is reached, {{call-with-response}} raises a
235condition of type {{(exn http redirect-depth-exceeded)}}.
236
237<parameter>(client-software [software-spec])</parameter>
238
239This is the names, versions and comments of the software packages that
240the client is using, for use in the {{user-agent}} header which is
241automatically added to each request by {{prepare-request}}.
242
243Defaults to {{(("Chicken Scheme HTTP-client" VERSION #f))}}, where
244{{VERSION}} is the version of this egg.
245
246==== Customising requests
247
248Given that http-client tries to do a lot "automagically", there will
249be occasions where you want more control.  One way to do that is to
250use {{call-with-response}}, but it's very low-level, so you'll end up
251reimplementing a lot of the functionality that
252{{call-with-input-request}} and {{with-input-from-request}} offer.
253
254Instead, http-client offers a parameter that allows you to tweak the
255request just before a connection is made:
256
257<parameter>(prepare-request [preparer])</parameter>
258
259Here, {{preparer}} is a procedure which will be called every time a
260connection is made.  This includes every request in a redirect chain,
261so you can decide for every URL in the chain what to do with the
262request.  The procedure receives and must return an intarweb request
263object.  The default implementation is {{default-prepare-request}}.
264
265'''CAVEAT''': If you decide to change the request-uri last-minute, you
266must also set the {{host}} header, because it will have already been
267initialized to the request-uri's host attribute.
268
269<procedure>(default-prepare-request req)</procedure>
270
271This is the default implementation of the {{prepare-request}}
272parameter.  It sets the {{User-Agent}} header from the
273{{client-software}} parameter and adds {{set-cookie}} headers which
274belong to the server and path from the request-uri.
275
276
277==== Connection management
278
279This egg tries to re-use connections that are marked as keep-alive, to
280avoid unnecessary overhead in establishing new connections when making
281multiple requests to the same server.  This is handled through a pool
282of idle connections from which the request procedures take the oldest
283active connection.
284
285<parameter>(max-idle-connections [count])</parameter>
286
287This controls the maximum allowed idle connections at any given time.
288When a connection would be returned to the pool, the connection will
289be discarded instead, if the maximum is exceeded.
290
291This value should always be well below the maximum number of available
292file descriptors for your operating system.
293
294Defaults to {{32}}.
295
296
297<procedure>(close-connection! uri)</procedure>
298
299Close the connection to the server associated with the URI.
300
301<procedure>(close-idle-connections!)</procedure>
302
303Close all remaining idle connections.  Note that connections that are
304currently in use will still be returned to the connection pool after
305their requests finish!
306
307<procedure>(close-all-connections!)</procedure>
308
309Deprecated alias for {{close-idle-connections!}}.
310
311==== Setting up custom server connections
312
313<procedure>(default-server-connector uri proxy)</procedure>
314
315The default value of the {{server-connector}} parameter.  This
316procedure creates a connection to the remote end for the given {{uri}}
317(an [[uri-common]] object) and returns two values: an input port and
318an output port.
319
320If {{proxy}} is not {{#f}} but an [[uri-common]] object, it will
321connect to that, instead.
322
323This connector supports plain {{http}} connections, and {{https}} if
324the {{openssl}} egg can be loaded (which it attempts to do on the
325fly).
326
327<parameter>(server-connector [connector])</parameter>
328
329This parameter holds a procedure which is invoked to establish a
330connection for an URI.
331
332The procedure should accept two [[uri-common]] objects as arguments:
333the first indicates the URI for which the connection is to be made and
334the second indicates the proxy through which the connection should be
335made, or {{#f}} if a direct connection should be made to the first
336URI's host and port.  It should return two values: an input port and
337an output port corresponding to the connection.
338
339This can be used for nonstandard or complex connections, like for
340example connecting to UNIX domain sockets or for supplying SSL/TLS
341client certificates.
342
343===== SSL client certificate authentication example
344
345This is how you would make a connection to an HTTPS server while
346supplying a client certificate.  Many thanks to Ryan Senior for the
347initial code.
348
349<enscript highlight="scheme">
350(use http-client uri-common openssl)
351
352(define (make-ssl-context/client-cert ca-cert-path cert-path key-path)
353  (let ((ssl-ctx (ssl-make-client-context 'tls)))
354
355    ;; Set up so the server's certificate can and will be verified
356    (ssl-load-suggested-certificate-authorities! ssl-ctx ca-cert-path)
357    (ssl-load-verify-root-certificates! ssl-ctx ca-cert-path)
358    (ssl-set-verify! ssl-ctx #t)
359
360    ;; Now load the client certificate
361    (ssl-load-certificate-chain! ssl-ctx cert-path)
362    (ssl-load-private-key! ssl-ctx key-path)
363
364    ;; Return the object we created
365    ssl-ctx))
366
367;; This creates server connectors associated with an SSL context
368(define (make-ssl-server-connector/context ssl-ctx)
369  (lambda (uri proxy)
370    (let ((remote-end (or proxy uri)))
371      (if (eq? 'https (uri-scheme remote-end))
372          ;; Only use ssl-connect for HTTPS connections
373          (ssl-connect (uri-host remote-end)
374                       (uri-port remote-end)
375                       ssl-ctx)
376          ;; Use http-client's default otherwise
377          (default-server-connector uri proxy)))))
378
379;; Now, make a context and matching connector, and register it
380(let ((ssl-ctx (make-ssl-context/client-cert
381                 "/etc/ssl/certs/ca.crt"
382                 "/etc/ssl/certs/my-client-cert.crt"
383                 "/etc/ssl/private/my-client-cert.key")))
384  (server-connector (make-ssl-server-connector/context ssl-ctx)))
385</enscript>
386
387Now, all requests made with any of the http-client procedures would
388authenticate with a server using the configured client certificate.
389
390==== Cookie management
391
392http-client's cookie management is supposed to be as automatic and
393DWIMmy as possible.  This means it will write any cookie as instructed
394by a server and all stored cookies are automatically sent back to the
395server upon a new request.
396
397However, in some cases you may want to take control of how cookies are
398stored.
399
400The API described here should be considered unstable and it may change
401dramatically when someone comes up with a better way to handle cookies.
402
403<procedure>(get-cookies-for-uri uri)</procedure>
404
405Fetch a list of all cookies which ought to be sent to the given URI.
406Cookies are vectors of two elements: a name/value pair and an alist of
407attributes.  In other words, these are the exact same values you can
408put in a {{cookie}} header.
409
410<procedure>(store-cookie! cookie-info set-cookie)</procedure>
411
412Store a cookie in the cookiejar corresponding to the Set-Cookie header
413given by {{set-cookie}}.  This overwrites any cookie that is equal to
414this cookie, as defined by RFC 2965, section 3.3.3.  Practically, this
415means that when the cookie's name, domain and path are equal to an
416existant one, it will be overwritten by the new one.  These attributes
417are taken from the {{cookie-info}} alist and expected to be there.
418
419Generally, attributes should be taken from {{set-cookie}}, but if
420missing they ought to be taken from the request URI that responded
421with the {{set-cookie}}.
422
423<enscript highlight="scheme">
424(store-cookie! `((path . ,(make-uri path: '(/ "")))
425                 (domain . "some.host.com")
426                 (secure . #t))
427               `#(("COOKIE_NAME" . "cookie-value")
428                  ((path . ,(make-uri path: '(/ ""))))))
429</enscript>
430
431<procedure>(delete-cookie! cookie-name cookie-info)</procedure>
432
433Removes any cookie from the cookiejar that is equal to the given
434cookie (again, in the sense of RFC 2965, section 3.3.3).
435The {{cookie-name}} must match and the {{path}} and {{domain}} values for
436the {{cookie-info}} alist must match.
437
438==== Authentication support
439
440When a 401 Unauthorized response is received, in most interactive
441clients, the user is normally asked to authenticate.  To support this
442type of interaction, http-client offers the following parameter:
443
444<parameter>(determine-username/password [HANDLER])</parameter>
445
446The procedure in this parameter is called whenever the remote
447host requests authentication via a 401 Unauthorized response.
448
449The {{HANDLER}} is a procedure of two arguments; the URI for the
450resource currently being requested and the realm (a string) which
451wants credentials.  The procedure should return two string values:
452the username and the password to use for authentication.
453
454The default value is a procedure which extracts the username and
455password components from the URI.
456
457For proxy authentication support, see {{determine-proxy-username/password}}
458in the next section.
459
460<parameter>(http-authenticators [AUTHENTICATORS])</parameter>
461
462This parameter allows for pluggable authentication schemes.
463{{AUTHENTICATORS}} is an alist mapping authentication scheme name
464to a procedure of 7 arguments:
465
466{{(lambda (response response-header new-request request-header uri realm writer) ...)}}
467
468Here, {{response}} is the response object, {{response-header}} is the
469name of the response header which required authentication - a symbol
470which is either {{www-authenticate}} or {{proxy-authenticate}}.
471
472{{new-request}} is the request that will be sent next, to be populated
473with additional headers by the authenticator procedure, and
474{{request-header}} is the name of the request header which is expected
475to be provided and supplied with extra details by the authenticator -
476also a symbol, which is either {{authorization}} or
477{{proxy-authorization}}.
478
479{{uri}} is the URI which was requested when the authorization was
480demanded (in case of {{www-authenticate}}, the protected resource) and
481{{realm}} is the authentication realm (a string).
482
483Finally {{writer}} is the writer procedure passed by the user or
484fabricated by {{call-with-input-request}} based on the user's form
485arguments.  It's always a procedure accepting a request object.
486This is only needed when full-request authentication is desired, to
487obtain a request body.
488
489==== Proxy support
490
491http-client has support for sending requests through proxy servers.
492
493<parameter>(determine-proxy [HANDLER])</parameter>
494
495Whenever a request is sent, the library invokes the procedure stored
496in this parameter to determine through what proxy to send the request,
497if any.
498
499The {{HANDLER}} procedure receives one argument, the URI about to be
500requested, and returns either an [[uri-common]] absolute URI object
501representing the proxy or {{#f}} if no proxy should be used.
502
503The URI's path and query, if present, are ignored; only the scheme
504and authority (host, port, username, password) are used.
505
506The default value of this parameter is {{determine-proxy-from-environment}}.
507
508<enscript highlight="scheme">
509(determine-proxy
510 (lambda (url)
511   (uri-reference "http://127.0.0.1:8888/")))
512</enscript>
513
514
515If you just want to disable proxy support, you can do:
516
517<enscript highlight="scheme">
518(determine-proxy (constantly #f))   ; From unit data-structures
519</enscript>
520
521<procedure>(determine-proxy-from-environment URI)</procedure>
522
523This procedure implements the common behaviour of HTTP software under
524UNIX:
525
526* First it checks if the requested URI's host (or an asterisk) is listed in the {{NO_PROXY}} environment variable (if suffixed with a port number, the port is also compared).  If a match is found, no proxy is used.
527* Then it will check if the {{$(protocol)_proxy}} or the {{$(PROTOCOL)_PROXY}} variable (in that order) are set.  If so, that's used.  {{protocol}} here actually means "scheme", so the URI's scheme is used, suffixed with {{_proxy}}. This means {{http_proxy}} is used for HTTP requests and {{https_proxy}} is used for HTTPS requests, but see the next point.
528* If the scheme is {{http}} and the environment variable {{REQUEST_METHOD}} is present, {{CGI_HTTP_PROXY}} is used instead of {{HTTP_PROXY}} to prevent a "[[https://httpoxy.org|httpoxy]]" attack.  This makes the assumption that {{REQUEST_METHOD}} is set because the library is being used in a CGI script.
529* If there's still no match, it looks for {{all_proxy}} or {{ALL_PROXY}}, in that order. If one of these environment variables are set, that value is used as a fallback proxy.
530* Finally, if none of these checks resulted in a proxy URI, no proxy will be used.
531
532Some UNIX software expects plain hostnames or hostname port
533combinations separated by colons, but (currently) this library expects
534full URIs, like most modern UNIX programs.
535
536<parameter>(determine-proxy-username/password [HANDLER])</parameter>
537
538The procedure in this parameter is called whenever the proxy requests
539authentication via a 407 Proxy Authentication Required response. This
540basically works the same as authentication against an origin server.
541
542The {{HANDLER}} is a procedure of two arguments; the URI for the
543''proxy'' currently being used and the realm (a string) which wants
544credentials.  The procedure should return two string values: the
545username and the password to use for authentication.
546
547The default value is a procedure which extracts the username and
548password components from the proxy's URI.
549
550
551=== Changelog
552
553* 0.18 Add response object to condition object raised when redirect limit is exceeded (thanks to Norman Gray).
554* 0.17 Preserve parsed URI path for requests, by avoiding re-encoding.  Fixes #1448 (thanks to [[/users/caolan-mcmahon|Caolan McMahon]])
555* 0.16 Replace heavy dependencies md5, message-digest and string-utils with simple-md5.
556* 0.15 Fix file descriptor leak when reader would raise exception (which also happened on 404 responses!)
557* 0.14 Fix off-by-one error in retry-attempts (thanks to "semarie").
558* 0.13 Enable SNI support for newly released openssl egg 1.9.0, use saner defaults like actually checking certificates. Add {{prepare-request}} procedure (thanks to [[/users/caolan-mcmahon|Caolan McMahon]])
559* 0.12.2 Tweak test timeouts some more.
560* 0.12.1 Tweak test timeouts so they hopefully won't fail as fast on Salmonella runs.
561* 0.12 Fix an endless loop in {{close-idle-connections!}} and a bug when {{max-idle-connections}} was zero (thanks to [[/users/mario-domenech-goulart|Mario Goulart]] for pointing out the endless loop).
562* 0.11 Add {{max-idle-connections}} to avoid FD exhaustion (thanks to [[/users/alaric-blagrave-snellpym|Alaric]] for pointing out this issue).  Add type and value check for uri argument (thanks to Lemonman for pointing this out).  Fix multipart sending of port-based files.  Add basic test suite.  Fix 303 redirect switch to {{GET}} method.  Use chunked encoding when using a custom writer procedure and there's no content-length header.
563* 0.10 Do not read {{HTTP_PROXY}} if {{REQUEST_METHOD}} is present (running in a CGI script), to prevent "[[https://httpoxy.org|httpoxy]]" attack (CVE-2016-6287).
564* 0.9 Add support for custom connector procedures.  Thanks to Ryan Senior for suggesting support for https client certificates, which this makes possible.
565* 0.8 Fix bug in multipart/form-data file uploads with non-file components in the form data causing a crash.  Thanks to Ryan Senior for reporting the bug and testing the fix.
566* 0.7.2 Add {{call-with-input-request*}}. Thanks to [[/users/mario-domenech-goulart|Mario Goulart]] for suggesting this.
567* 0.7.1 Fix delimited port handling of {{peek-char}} which caused mysterious openssl errors.  Thanks to [[/users/mario-domenech-goulart|Mario Goulart]] for a reproducible test case.
568* 0.7 Reduce CPU usage by implementing custom {{read-string!}} and {{read-line}} procedures in {{make-delimited-input-port}}. Improved error reporting (show URI as string, and always include it in error messages). Gracefully handle premature disconnection by retrying (as per RFC2616, 8.2.4).  Make openssl an optional dependency to make it easier to install on Windows.
569* 0.6.1 Work around a bug in {{read-string!}} in CHICKEN core which caused random errors.
570* 0.6 Provide a proper condition when encountering unsupported URI schemes (thanks to [[/users/christian-kellermann|Christian Kellermann]]).  Fix response body reading in error situations (thanks to [[/users/andyjpb|Andy Bennett]]).  Update request writer to use new {{finish-request-body}} from intarweb 1.0.
571* 0.5.1 Restore compatibility with message-digest and string-utils egg.
572* 0.5 Improve detection of dropped connections (prevents unneccessary "connection reset" exceptions to propagate into the program). Simplify interface by switching to {{POST}} when a {{writer}} is given to {{with-input-from-request}} and {{call-with-input-request}}.  Add support for multipart forms (file upload). Fix error in case of missing username when authorization was required (introduced by version 0.4.2). Put loop call in tail position (thanks to [[/users/felix-winkelmann|Felix]]) Automatically discard remaining data on the input port, if any, to avoid problems on subsequent requests. Add rudimentary support for parameterizable authentication schemes.
573* 0.4.2 Allow missing passwords in URIs for authentication
574* 0.4.1 Fix connection status check so when the remote end closed the connection we don't try to read from it anymore (thanks to Daishi Kato and Thomas Hintz)
575* 0.4 Fix redirection code on 303, and off-by-1 mistake in redirects count (thanks to Moritz Heidkamp). Add arguments to exn objects (thanks to Christian Kellermann). Also accept an empty alist for POSTdata. Fix URI path comparisons in cookies (thanks to Daishi Kato)
576* 0.3 Fixed handling of missing Path parameters in set-cookie headers. Reported by Hugo Arregui. Improve set-cookie handling by only passing Path and Domain when matching Set-Cookie header included those parameters.
577* 0.2 Added proxy support and many many bugfixes
578* 0.1 Initial version
579
580=== License
581
582  Copyright (c) 2008-2018, Peter Bex
583  Parts copyright (c) 2000-2004, Felix L. Winkelmann
584  All rights reserved.
585 
586  Redistribution and use in source and binary forms, with or without
587  modification, are permitted provided that the following conditions are
588  met:
589 
590  Redistributions of source code must retain the above copyright
591  notice, this list of conditions and the following disclaimer.
592 
593  Redistributions in binary form must reproduce the above copyright
594  notice, this list of conditions and the following disclaimer in the
595  documentation and/or other materials provided with the distribution.
596 
597  Neither the name of the author nor the names of its contributors may
598  be used to endorse or promote products derived from this software
599  without specific prior written permission.
600 
601  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
602  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
603  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
604  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
605  COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
606  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
607  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
608  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
609  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
610  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
611  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
612  OF THE POSSIBILITY OF SUCH DAMAGE.
Note: See TracBrowser for help on using the repository browser.