diff --git a/collects/net/scribblings/dns.scrbl b/collects/net/scribblings/dns.scrbl new file mode 100644 index 0000000000..b586f983b2 --- /dev/null +++ b/collects/net/scribblings/dns.scrbl @@ -0,0 +1,76 @@ +#lang scribble/doc +@(require "common.ss" + (for-label net/dns + net/dns-unit + net/dns-sig)) + +@title{DNS: Domain Name Service Queries} + +@defmodule[net/dns]{The @schememodname[net/dns] module provides +utilities for looking up hostnames. + +Thanks to Eduardo Cavazos and Jason Crowe for repairs and +improvements.} + +@; ---------------------------------------- + +@section[#:tag "dns-proc"]{Functions} + +@defproc[(dns-get-address [nameserver string?] + [address string?]) + string?]{ + +Consults the specified nameserver (normally a numerical address like +@scheme["128.42.1.30"]) to obtain a numerical address for the given +Internet address. + +The query record sent to the DNS server includes the "recursive" bit, +but @scheme[dns-get-address] also implements a recursive search itself +in case the server does not provide this optional feature.} + + +@defproc[(dns-get-name [nameserver string?] + [address string?]) + string?]{ + +Consults the specified nameserver (normally a numerical address like +@scheme["128.42.1.30"]) to obtain a name for the given numerical +address.} + + +@defproc[(dns-get-mail-exchanger [nameserver string?] + [address string?]) + string?]{ + +Consults the specified nameserver to obtain the address for a mail +exchanger the given mail host address. For example, the mail exchanger +for @scheme["ollie.cs.rice.edu"] might be @scheme["cs.rice.edu"].} + + + +@defproc[(dns-find-nameserver) (or/c string? false/c)]{ + +Attempts to find the address of a nameserver on the present system. +Under Unix, this procedure parses @filepath{/etc/resolv.conf} to +extract the first nameserver address. Under Windows, it runs +@exec{nslookup.exe}.} + +@; ---------------------------------------- + +@section{DNS Unit} + +@defmodule[net/dns-unit] + +@defthing[dns@ unit?]{ + +Imports nothing, exports @scheme[dns^].} + +@; ---------------------------------------- + +@section{DNS Signature} + +@defmodule[net/dns-sig] + +@defsignature[dns^ ()]{} + +Includes everything exported by the @schememodname[net/dns] module. diff --git a/collects/net/scribblings/head.scrbl b/collects/net/scribblings/head.scrbl new file mode 100644 index 0000000000..9a17add642 --- /dev/null +++ b/collects/net/scribblings/head.scrbl @@ -0,0 +1,239 @@ +#lang scribble/doc +@(require "common.ss" + scribble/eval + scribble/struct + (for-label net/head + net/head-unit + net/head-sig)) + +@(define head-eval (make-base-eval)) +@interaction-eval[#:eval head-eval (require net/head)] + +@title{headers: Parsing and Constructing} + +@defmodule[net/head]{The @schememodname[net/head] module provides +utilities for parsing and constructing RFC 822 headers +@cite["RFC822"], which are used in protocols such as HTTP, SMTP, and +NNTP.} + +A @deftech{header} is represented as a string or byte string +containing CRLF-delimited lines. Each field within the header spans +one or more lines. In addition, the header ends with two CRLFs +(because the first one terminates the last field, and the second +terminates the header). + +@; ---------------------------------------- + +@section{Functions} + +@defthing[empty-header string?]{ + +The string @scheme["\r\n\r\n"], which corresponds to the empty header. +This value is useful for building up headers with +@scheme[insert-field] and @scheme[append-headers].} + + +@defproc[(validate-header [candidate (or string? bytes?)]) void?]{ + +Checks that @scheme[candidate] matches RFC 822. If it does not, an +exception is raised.} + + +@defproc[(extract-field [field (or/c string? bytes?)] [header (or/c string? bytes?)]) + (or/c string? bytes? false/c)]{ + +Returns the header content for the specified field, or @scheme[#f] if +the field is not in the header. The @scheme[field] string should not +end with @scheme[":"], and it is used case-insensitively. The returned +string will not contain the field name, color separator, or CRLF +terminator for the field; however, if the field spans multiple lines, +the CRLFs separating the lines will be intact. + +The @scheme[field] and @scheme[header] arguments must be both strings +or both byte strings, and the result (if not @scheme[#f]) is of the +same type. + +@examples[ +#:eval head-eval +(extract-field "TO" (insert-field "to" "me@localhost" + empty-header)) +]} + +@defproc[(extract-all-fields [header (or/c string? bytes?)]) + (listof (cons/c (or/c string? bytes?) + (or/c string? bytes?)))]{ + +Returns an association-list version of the header; the case of the +field names is preserved, as well as the order and duplicate uses of a +field name. + +The result provides strings if @scheme[header] is a string, byte +strings if @scheme[header] is a byte string.} + + +@defproc[(remove-field [field (or/c string? bytes?)] + [header (or/c string? bytes?)]) + (or/c string? bytes?)]{ + +Creates a new header by removing the specified field from +@scheme[header] (or the first instance of the field, if it occurs +multiple times). If the field is not in @scheme[header], then the +return value is @scheme[header]. + +The @scheme[field] and @scheme[header] arguments must be both strings +or both byte strings, and the result is of the same type.} + + +@defproc[(insert-field [field (or/c string? bytes?)] + [value (or/c string? bytes?)] + [header (or/c string? bytes?)]) + (or/c string? bytes?)]{ + +Creates a new header by prefixing the given @scheme[header] with the +given @scheme[field]-@scheme[value] pair. The @scheme[value] string +should not contain a terminating CRLF, but a multi-line value (perhaps +created with @scheme[data-lines->data]) may contain separator CRLFs. + +The @scheme[field], @scheme[value], and @scheme[header] arguments must +be all strings or all byte strings, and the result is of the same +type.} + + +@defproc[(replaces-field [field (or/c string? bytes?)] + [value (or/c string? bytes? false/c)] + [header (or/c string? bytes?)]) + (or/c string? bytes?)]{ + +Composes @scheme[remove-field] and (if @scheme[value] is not +@scheme[#f]) @scheme[insert-field].} + +@defproc[(append-headers [header1 (or/c string? bytes?)] + [header2 (or/c string? bytes?)]) + (or/c string? bytes?)]{ + +Appends two headers. + +The @scheme[header1] and @scheme[header2] arguments must be both +strings or both byte strings, and the result is of the same type.} + + +@defproc[(standard-message-header [from string?] + [to (listof -string?)] + [cc (listof strings?)] + [bcc (listof string?)] + [subject string?]) + string?]{ + +Creates a standard mail header given the sender, various lists of +recipients, a subject. A @scheme["Date"] field is added to the header +automatically, using the current time. + +The BCC recipients do not actually appear in the header, but they're +accepted anyway to complete the abstraction.} + + +@defproc[(data-lines->data (listof string?)) string?]{ + +Merges multiple lines for a single field value into one string, +adding CRLF-TAB separators.} + + +@defproc[(extract-addresses [line string?] + [kind (one-of/c 'name 'address + 'full 'all)]) + (or/c (listof string?) + (listof (list/c string? string? string?)))]{ + +Parses @scheme[string] as a list of comma-delimited mail addresses, +raising an exception if the list is ill-formed. This procedure can be +used for single-address strings, in which case the returned list +contains only one address. + +The @scheme[kind] argument specifies which portion of an address +should be returned: + +@itemize[ + + @item{@scheme['name] --- the free-form name in the address, or the + address itself if no name is available. + + @examples[ + #:eval head-eval + (extract-addresses "John Doe " 'name) + (extract-addresses "doe@localhost (Johnny Doe)" 'name) + (extract-addresses "doe@localhost" 'name) + (extract-addresses " \"Doe, John\" , jane" + 'name) + ]} + + @item{@scheme['address] --- just the mailing address, without any free-form + names. + + @examples[ + #:eval head-eval + (extract-addresses "John Doe " 'address) + (extract-addresses "doe@localhost (Johnny Doe)" 'address) + (extract-addresses "doe@localhost" 'address) + (extract-addresses " \"Doe, John\" , jane" + 'address) + ]} + + @item{@scheme['full] --- the full address, essentially as it appears in the + input, but normalized. + + @examples[ + #:eval head-eval + (extract-addresses "John Doe < doe@localhost >" 'full) + (extract-addresses " doe@localhost (Johnny Doe)" 'full) + (extract-addresses "doe@localhost" 'full) + (extract-addresses " \"Doe, John\" , jane" + 'full) + ]} + + @item{@scheme['all] --- a list containing each of the three possibilities: + free-form name, address, and full address (in that + order). + + @examples[ + #:eval head-eval + (extract-addresses "John Doe " 'all) + (extract-addresses "doe@localhost (Johnny Doe)" 'all) + (extract-addresses "doe@localhost" 'all) + (extract-addresses " \"Doe, John\" , jane" + 'all) + ]} + +]} + + +@defproc[(assemble-address-field (addrs (listof string?))) string?]{ + +Creates a header field value from a list of addresses. The addresses +are comma-separated, and possibly broken into multiple lines. + +@examples[ +#:eval head-eval +(assemble-address-field '("doe@localhost" + "Jane ")) +]} + + +@; ---------------------------------------- + +@section{Header Unit} + +@defmodule[net/head-unit] + +@defthing[head@ unit?]{ + +Imports nothing, exports @scheme[head^].} + +@; ---------------------------------------- + +@section{Header Signature} + +@defmodule[net/head-sig] + +@defsignature[head^ ()]{} + +Includes everything exported by the @schememodname[net/head] module. diff --git a/collects/net/scribblings/imap.scrbl b/collects/net/scribblings/imap.scrbl index 9e2c24acc4..1ffeee1ed1 100644 --- a/collects/net/scribblings/imap.scrbl +++ b/collects/net/scribblings/imap.scrbl @@ -43,9 +43,9 @@ @title{IMAP: Reading Mail} -@defmodule[net/imap]{The @schememodname[net/imap] module provides for -the client side of Internet Message Access Protocol version 4rev1 -@cite["RFC2060"].} +@defmodule[net/imap]{The @schememodname[net/imap] module provides +utilities for the client side of Internet Message Access Protocol +version 4rev1 @cite["RFC2060"].} @; ---------------------------------------- @@ -497,3 +497,22 @@ mailbox path names.} Returns a list of IMAP flags for the given mailbox. See also @scheme[imap-flag->symbol].} +@; ---------------------------------------- + +@section{IMAP Unit} + +@defmodule[net/imap-unit] + +@defthing[imap@ unit?]{ + +Imports nothing, exports @scheme[imap^].} + +@; ---------------------------------------- + +@section{IMAP Signature} + +@defmodule[net/imap-sig] + +@defsignature[imap^ ()]{} + +Includes everything exported by the @schememodname[net/imap] module. diff --git a/collects/net/scribblings/net.scrbl b/collects/net/scribblings/net.scrbl index 4262bebaec..4be7c90bc5 100644 --- a/collects/net/scribblings/net.scrbl +++ b/collects/net/scribblings/net.scrbl @@ -6,13 +6,16 @@ @table-of-contents[] @include-section["url.scrbl"] +@include-section["uri-codec.scrbl"] @include-section["sendurl.scrbl"] @include-section["smtp.scrbl"] @include-section["cgi.scrbl"] @include-section["sendmail.scrbl"] +@include-section["head.scrbl"] @include-section["nntp.scrbl"] @include-section["pop3.scrbl"] @include-section["imap.scrbl"] +@include-section["dns.scrbl"] @include-section["gifwrite.scrbl"] @(bibliography @@ -21,6 +24,13 @@ #:title "Common Gateway Interface (CGI/1.1)" #:url "http://hoohoo.ncsa.uiuc.edu/cgi/") + (bib-entry #:key "RFC822" + #:title "Standard for the Format of ARPA Internet Text Messages" + #:author "David Crocker" + #:location "RFC" + #:url "http://www.ietf.org/rfc/rfc0822.txt" + #:date "1982") + (bib-entry #:key "RFC977" #:title "Network News Transfer Protocol" #:author "Brian Kantor and Phil Lapsley" @@ -28,6 +38,13 @@ #:url "http://www.ietf.org/rfc/rfc0977.txt" #:date "1986") + (bib-entry #:key "RFC1738" + #:title "Uniform Resource Locators (URL)" + #:author "T. Berners-Lee, L. Masinter, and M. McCahill" + #:location "RFC" + #:url "http://www.ietf.org/rfc/rfc1738.txt" + #:date "1994") + (bib-entry #:key "RFC1939" #:title "Post Office Protocol - Version 3" #:author "J. Myers and M. Rose" diff --git a/collects/net/scribblings/uri-codec.scrbl b/collects/net/scribblings/uri-codec.scrbl new file mode 100644 index 0000000000..a8a6b9a229 --- /dev/null +++ b/collects/net/scribblings/uri-codec.scrbl @@ -0,0 +1,147 @@ +#lang scribble/doc +@(require "common.ss" + scribble/bnf + scribble/eval + (for-label net/url + net/uri-codec + net/uri-codec-unit + net/uri-codec-sig)) + +@(define uri-codec-eval (make-base-eval)) +@interaction-eval[#:eval uri-codec-eval (require net/uri-codec)] + +@title{URI Codec: Encoding and Decoding URIs} + +@defmodule[net/uri-codec]{The @schememodname[net/uri-codec] module +provides utilities for encoding and decoding strings using the URI +encoding rules given in RFC 2396 @cite["RFC2396"], and to encode and +decode name/value pairs using the +@tt{application/x-www-form-urlencoded} mimetype given the in HTML 4.0 +specification. There are minor differences between the two encodings.} + +The URI encoding uses allows a few characters to be represented as-is: +@litchar{a} through @litchar{z}, @litchar{A} through @litchar{Z}, +@litchar{0}-@litchar{9}, @litchar{-}, @litchar{_}, @litchar{.}, +@litchar{!}, @litchar{~}, @litchar{*}, @litchar{'}, @litchar{(} and +@litchar{)}. The remaining characters are encoded as +@litchar{%}@nonterm{xx}, where @nonterm{xx} is the two-character hex +representation of the integer value of the character (where the +mapping character--integer is determined by US-ASCII if the integer is +less than 128). + +The encoding, in line with RFC 2396's recommendation, represents a +character as-is, if possible. The decoding allows any characters +to be represented by their hex values, and allows characters to be +incorrectly represented as-is. + +The rules for the @tt{application/x-www-form-urlencoded} mimetype +given in the HTML 4.0 spec are: + +@itemize[ + + @item{Control names and values are escaped. Space characters are + replaced by @litchar{+}, and then reserved characters are escaped as + described in RFC 1738, section 2.2: Non-alphanumeric characters are + replaced by @litchar{%}@nonterm{xx} representing the ASCII code of + the character. Line breaks are represented as CRLF pairs: + @litchar{%0D%0A}. Note that RFC 2396 supersedes RFC 1738 + @cite["RFC1738"].} + + @item{The control names/values are listed in the order they appear + in the document. The name is separated from the value by @litchar{=} + and name/value pairs are separated from each other by either + @litchar{;} or @litchar{&}. When encoding, @litchar{;} is used as + the separator by default. When decoding, both @litchar{;} and + @litchar{&} are parsed as separators by default.} + +] + +These rules differs slightly from the straight encoding in RFC 2396 in +that @litchar{+} is allowed, and it represents a space. The +@schememodname[net/uri-codec] library follows this convention, +encoding a space as @litchar{+} and decoding @litchar{+} as a space. +In addtion, since there appear to be some brain-dead decoders on the +web, the library also encodes @litchar{!}, @litchar{~}, @litchar{'}, +@litchar{(}, and @litchar{)} using their hex representation, which is +the same choice as made by the Java's @tt{URLEncoder}. + +@; ---------------------------------------- + +@section[#:tag "uri-codec-proc"]{Functions} + +@defproc[(uri-encode [str string?]) string?]{ + +Encode a string using the URI encoding rules.} + + +@defproc[(uri-decode [str string?]) string?]{ + +Decode a string using the URI decoding rules.} + + +@defproc[(form-urlencoded-encode [str string?]) string?]{ + +Encode a string using the @tt{application/x-www-form-urlencoded} +encoding rules. The result string contains no non-ASCII characters.} + + +@defproc[(form-urlencoded-deecode [str string?]) string?]{ + +Decode a string encoded using the +@tt{application/x-www-form-urlencoded} encoding rules.} + + +@defproc[(alist->form-urlencoded [alist (listof (cons/c symbol? string?))]) + string?]{ + +Encode an association list using the +@tt{application/x-www-form-urlencoded} encoding rules. + +The @scheme[current-alist-separator-mode] parameter determines the +separator used in the result.} + + +@defproc[(form-urlencoded->alist [str string]) + (listof (cons/c symbol? string?))]{ + +Decode a string encoded using the +@tt{application/x-www-form-urlencoded} encoding rules into an +association list. All keys are case-folded for conversion to symbols. + +The @scheme[current-alist-separator-mode] parameter determines the way +that separators are parsed in the input.} + + +@defparam[current-alist-separator-mode mode + (one-of/c 'amp 'semi 'amp-or-semi 'semi-or-amp)]{ + +A parameter that determines the separator used/recognized between +associations in @scheme[form-urlencoded->alist], +@scheme[alist->form-urlencoded], @scheme[url->string], and +@scheme[string->url]. + +The default value is @scheme['amp-or-semi], which means that both +@litchar{&} and @litchar{;} are treated as separators when parsing, +and @litchar{&} is used as a separator when encoding. The other modes +use/recognize only of the separators. + +@examples[ +#:eval uri-codec-eval +(define ex '((x . "foo") (y . "bar") (z . "baz"))) +(code:line (current-alist-separator-mode 'amp) (code:comment #, @t{try @scheme['amp]...})) +(form-urlencoded->alist "x=foo&y=bar&z=baz") +(form-urlencoded->alist "x=foo;y=bar;z=baz") +(alist->form-urlencoded ex) +(code:line (current-alist-separator-mode 'semi) (code:comment #, @t{try @scheme['semi]...})) +(form-urlencoded->alist "x=foo;y=bar;z=baz") +(form-urlencoded->alist "x=foo&y=bar&z=baz") +(alist->form-urlencoded ex) +(code:line (current-alist-separator-mode 'amp-or-semi) (code:comment #, @t{try @scheme['amp-or-semi]...})) +(form-urlencoded->alist "x=foo&y=bar&z=baz") +(form-urlencoded->alist "x=foo;y=bar;z=baz") +(alist->form-urlencoded ex) +(code:line (current-alist-separator-mode 'semi-or-amp) (code:comment #, @t{try @scheme['semi-or-amp]...})) +(form-urlencoded->alist "x=foo&y=bar&z=baz") +(form-urlencoded->alist "x=foo;y=bar;z=baz") +(alist->form-urlencoded ex) +]} diff --git a/collects/net/scribblings/url.scrbl b/collects/net/scribblings/url.scrbl index f0aa400672..0317f38c0f 100644 --- a/collects/net/scribblings/url.scrbl +++ b/collects/net/scribblings/url.scrbl @@ -22,8 +22,7 @@ you have a regular input port with which to process the document, as with any other file. Currently the only supported protocols are @scheme["http"] and -sometimes @scheme["file"]. See also the @schememodname[net/news] -library. +sometimes @scheme["file"]. @section{URL Structure} @@ -284,7 +283,7 @@ something like @litchar{1.0} or @litchar{1.1}, @nonterm{code} is an exact integer for the response code, and @nonterm{message} is arbitrary text without a return or newline. -The @schememodname[net/head.ss] library provides procedures, such as +The @schememodname[net/head] library provides procedures, such as @scheme[extract-field] for manipulating the header. Since web servers sometimes return mis-formatted replies, diff --git a/collects/scribblings/reference/breaks.scrbl b/collects/scribblings/reference/breaks.scrbl index b54ea64553..e89776049b 100644 --- a/collects/scribblings/reference/breaks.scrbl +++ b/collects/scribblings/reference/breaks.scrbl @@ -76,7 +76,7 @@ exception is raised, but not both. Scheme therefore supplies which does permit the implementation of such an exclusive guarantee: @schemeblock[ -(parameterize ([break-enabled #f]) +(parameterize-break #f (with-handlers ([exn:break? (lambda (x) (void))]) (semaphore-wait/enable-break s))) ]