The Trunk: WebClient-Help-ar.10.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The Trunk: WebClient-Help-ar.10.mcz

commits-2
Tobias Pape uploaded a new version of WebClient-Help to project The Trunk:
http://source.squeak.org/trunk/WebClient-Help-ar.10.mcz

==================== Summary ====================

Name: WebClient-Help-ar.10
Author: ar
Time: 31 August 2010, 11:09:04.966 pm
UUID: 4c7a5c81-01c4-fc4d-a98e-1271bbd0c47d
Ancestors: WebClient-Help-ar.9

Update change log for WebClient and WebServer 1.4.

==================== Snapshot ====================

SystemOrganization addCategory: #'WebClient-Help'!

CustomHelp subclass: #WebClientHelp
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'WebClient-Help'!

----- Method: WebClientHelp class>>authentication (in category 'pages') -----
authentication
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #authentication"
        ^HelpTopic
                title: 'Authentication'
                contents:
'WebClient supports basic and digest authentication by default. WebClient delegates the retrieval of username/password to WebUtils which prompts the user for credentials.

WebClient can either be supplied with specific credentials to be used or custom credentials handlers, for example:

        | client |
        client := WebClient new.
        client username: ''squeak''.
        client password: ''squeak''.
        client httpGet: ''http://www.squeak.org/protected''.

Proxy authentication works the same way as authentication but operates on a different authentication context to allow different sets of credentials to work.
!!
]style[(288 1 1 1 6 1 1 2 6 1 2 11 3 3 6 1 9 1 8 3 6 1 9 1 8 3 6 1 8 1 33 2 158),cblack;,cgray;,cblack;,c107107107,cblack;,cgray;,cblack;,c107107107,cblack;,b,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,!!' readStream nextChunkText!

----- Method: WebClientHelp class>>bookName (in category 'accessing') -----
bookName
        "Returns the name of the custom help book"

        ^'WebClient'!

----- Method: WebClientHelp class>>changeLog (in category 'pages') -----
changeLog
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #changeLog"
        ^HelpTopic
                title: 'Version History'
                contents:
'WebClient 1.4:
* Fixes cookie handling to be in line with RFC 2109
* Provide the final redirect url in requests
* OAuth support via WebUtils.
* Support for POST using chunked transfer-encoding

WebClient 1.3:
* Added logging in common log format
* Added support for SSL/TLS via SqueakSSL.

WebClient 1.2:
* Added support for multipart/form-data posts
* Added WebSocket support

WebClient 1.1:
* Added support for HEAD, TRACE, OPTIONS, and PUT methods

WebClient 1.0:
* Initial release.
!!' readStream nextChunkText!

----- Method: WebClientHelp class>>cookieSupport (in category 'pages') -----
cookieSupport
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #cookieSupport"
        ^HelpTopic
                title: 'Cookie Support'
                contents:
'WebClient supports session cookies. Cookies are preserved within one WebClient session but not across multiple session (cookies can be copied or shared between WebClients which makes it easy to support where needed). Support for cookies can be disabled via WebClient''s #acceptCookies: property.
!!' readStream nextChunkText!

----- Method: WebClientHelp class>>introduction (in category 'pages') -----
introduction
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #introduction"
        ^HelpTopic
                title: 'Introduction'
                contents:
'WebClient is a simple, yet reasonably complete HTTP client. WebClient uses HTTP 1.1, supports proxies (both authenticating and not), redirect support and authentication.

WebClient comes with WebServer, an HTTP server implementation with a similarly simple yet reasonably complete approach.!!' readStream nextChunkText!

----- Method: WebClientHelp class>>multipleRequests (in category 'pages') -----
multipleRequests
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #multipleRequests"
        ^HelpTopic
                title: 'Multiple Requests'
                contents:
'WebClient can and should be used for multiple requests to the same host. This will ensure persistent connections as well as having cookies processed properly within one session:

        | client resp |
        client := WebClient new.
        resp := client httpGet: ''http://www.squeak.org/''.
        resp := client httpGet: ''http://www.squeak.org/Download''.
        resp := client httpGet: ''http://www.squeak.org/Features''.
        client close.

One important issue to keep in mind is that because WebClient is optimized for persistent connections, you need to close it when you are done. That is not true for WebClient''s class-side convenience APIs, which prefetch the response and close the socket. Generally speaking, whenever you say ''WebClient new'' you need to close the client when you''re done (however, you can do so by sending #close to a response you''ve received). For example:

        "Convenience API. Don''t need to close, but prefetches result."
        WebClient httpGet: ''http://www.squeak.org''.

        | client resp |
        "Regular use. Create WebClient, return after header is read ..."
        client := WebClient new.
        [response := client httpGet: ''http://www.squeak.org/''.
        "... then fetch (or stream) the content ..."
        response content.
        ] ensure:[
                "... and close the client when done."
                client close.
        ].!!
]style[(179 1 1 1 6 1 4 1 1 2 6 1 2 11 3 3 4 1 2 1 6 1 8 1 24 3 4 1 2 1 6 1 8 1 32 3 4 1 2 1 6 1 8 1 32 3 6 1 5 2 443 1 62 12 8 1 23 4 1 1 6 1 4 1 1 2 64 1 1 6 1 2 11 3 4 8 1 2 1 6 1 8 1 24 3 44 2 8 1 7 5 7 4 37 3 6 1 5 5),cblack;,cgray;,cblack;,c107107107,cblack;,c107107107,cblack;,cgray;,cblack;,c107107107,cblack;,b,cblack;,c000000127,cblack;,c107107107,cblack;,b,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c107107107,cblack;,b,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c107107107,cblack;,b,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c107107107,cblack;,c000000127,cblack;,,cblack;,c000127127,cblack;,c000000127,cblack;,c127000127,cblack;,cgray;,cblack;,c107107107,cblack;,c107107107,cblack;,cgray;,cblack;,c000127127,,cblack;,c107107107,cblack;,b,cblack;,c000000127,cblack;,c107107107,cblack;,b,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c000127127,cblack;,c107107107,cblack;,c000000127,cblack;,c000000127,cblack;,c000127127,cblack;,c107107107,cblack;,c000000127,cblack;!!' readStream nextChunkText!

----- Method: WebClientHelp class>>pages (in category 'accessing') -----
pages
        "Returns a collection of method selectors to return the pages of the custom help book"
               
        ^#(introduction webClientRequests webClientResponses multipleRequests authentication redirectSupport proxySupport cookieSupport changeLog)!

----- Method: WebClientHelp class>>proxySupport (in category 'pages') -----
proxySupport
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #proxySupport"
        ^HelpTopic
                title: 'Proxy Support'
                contents:
'WebClient supports connecting via http proxies, including authenticating proxies. WebClient delegates proxy detection to its ProxyHandler which is responsible for performing the proper actions. Proxy authentication is handled in a similar way as regular authentication. The defaults are implemented in WebUtils.
!!' readStream nextChunkText!

----- Method: WebClientHelp class>>redirectSupport (in category 'pages') -----
redirectSupport
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #redirectSupport"
        ^HelpTopic
                title: 'Redirect Handling'
                contents:
'WebClient handles http redirect requests (3xx) transparently. WebClient detects infinite redirect loops and gives up after a certain number of attempts, returning the redirect (3xx) response which caused it to give up. Users of WebClient will only see 3xx responses if WebClient has given up (i.e., returning a 3xx should be considered an error).

Redirect handling can be disabled by setting #allowRedirect property to the desired value. When disabled, WebClient will not attempt to perform any redirect handling.!!' readStream nextChunkText!

----- Method: WebClientHelp class>>webClientRequests (in category 'pages') -----
webClientRequests
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #webClientRequests"
        ^HelpTopic
                title: 'Using WebClient'
                contents:
'The simplest form to use WebClient is by one of its convenience APIs:

        WebClient httpGet: ''http://www.squeak.org/''.
        WebClient httpPost: ''http://www.squeak.org/'' content:''Hello Squeak'' type: ''text/plain''.

For more elaborate use of headers and some other options in the request, a client can utilize modified variants:

        WebClient new httpGet: ''http://www.squeak.org/'' do:[:req|
                "Set an if-modified-since header"
                req headerAt: ''If-Modified-Since'' put: ''Sat, 29 Oct 1994 19:43:31 GMT''.
                "Add several accept headers"
                req addHeader: ''Accept'' value: ''text/plain''.
                req addHeader: ''Accept'' value: ''application/x-foo-bar''.
                req addHeader: ''Accept'' value: ''image/jpg''.
        ].

The set of utility methods is limited to a few useful ones but it is easy to do the setup on your own:

        | url client request data |
        data := ''Hello Squeak''. "POST data"
        url := ''http://www.squeak.org/''. "POST url"
        client := WebClient new initializeFromUrl: url. "sets host etc"
        request := client requestWithUrl: url. "sets path etc"
        request method: ''POST''. "sets method"
        request headerAt: ''Content-Length'' put: data size.
        request headerAt: ''Content-Type'' put: ''text/plain''.
        "... any other headers required ..."
        ^client sendRequest: request
                content: data readStream
                size: data size.

The utility methods like httpGet: etc. are similarly simple requests.
!!
]style[(71 11 8 1 24 13 9 1 24 1 8 14 1 5 1 12 2 115 11 3 1 8 1 24 1 3 2 3 1 3 33 3 3 1 9 1 19 1 4 1 31 4 28 3 3 1 10 1 8 1 6 1 12 4 3 1 10 1 8 1 6 1 23 4 3 1 10 1 8 1 6 1 11 6 105 1 1 1 3 1 6 1 7 1 4 1 1 2 4 1 2 1 14 9 11 2 3 1 2 1 24 7 10 2 6 1 2 11 3 1 18 1 3 4 15 2 7 1 2 1 6 1 15 1 3 6 15 2 7 1 7 1 6 8 13 2 7 1 9 1 16 1 4 1 4 1 4 3 7 1 9 1 14 1 4 1 12 3 36 2 1 6 1 12 1 7 4 8 1 4 1 10 3 5 1 4 1 4 2 71),cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,c000127127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000127127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,,cblack;,cgray;,cblack;,c107107107,cblack;,c107107107,cblack;,c107107107,cblack;,c107107107,cblack;,cgray;,cblack;,c107107107,cblack;,b,cblack;,c127000127,cblack;,c000127127,cblack;,c107107107,cblack;,b,cblack;,c127000127,cblack;,c000127127,cblack;,c107107107,cblack;,b,cblack;,c000000127,cblack;,c000000127,cblack;,c107107107,cblack;,c000127127,cblack;,c107107107,cblack;,b,cblack;,c107107107,cblack;,c000000127,cblack;,c107107107,cblack;,c000127127,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c000127127,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000127127,cblack;,c127000000,c107107107,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,!!' readStream nextChunkText!

----- Method: WebClientHelp class>>webClientResponses (in category 'pages') -----
webClientResponses
        "This method was automatically generated. Edit it using:"
        "WebClientHelp edit: #webClientResponses"
        ^HelpTopic
                title: 'Responses'
                contents:
'The WebClient request methods return a WebResponse that the client can process:

        | resp |
        resp := WebClient httpGet: ''http://www.squeak.org/''.
        resp isSuccess ifFalse:[^self error: resp status].
        "Process the content from the response"
        ^resp content

In addition, content can be streamed from the response so that it does not need to be downloaded all at once:

        | client resp file |
        client := WebClient new.
        [resp := client httpGet: ''http://www.squeak.org/''.
        resp isSuccess ifFalse:[^self error: resp status].
        "Stream the content from the response"
        file := FileStream newFileNamed: ''page.html''.
        resp streamTo: file
                        size: resp contentLength
                        progress:[:total :amount].
        file close] ensure:[client close].

The progress block in the above can be omitted but has been included in this example to illustrate its usage. The block takes a total length (which can be nil if the length is not known) and the amount that has been loaded.
!!
]style[(81 1 1 1 4 1 1 2 4 1 2 11 8 1 24 3 4 1 9 1 8 1 5 1 6 1 4 1 6 4 39 2 1 4 1 7 1 112 1 1 1 6 1 4 1 4 1 1 2 6 1 2 11 3 4 4 1 2 1 6 1 8 1 24 3 4 1 9 1 8 1 5 1 6 1 4 1 6 1 3 38 2 4 1 2 12 13 1 11 3 4 1 9 1 4 5 5 1 4 1 13 4 9 1 1 5 2 6 1 3 4 1 5 2 7 1 6 1 5 3 225),cblack;,cgray;,cblack;,c107107107,cblack;,cgray;,cblack;,c107107107,cblack;,b,cblack;,c000000127,cblack;,c127000127,cblack;,c107107107,cblack;,c000000127,cblack;,c000000127,cblack;,c127000000,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,c000127127,cblack;,c127000000,c107107107,cblack;,c000000127,cblack;,,cblack;,cgray;,cblack;,c107107107,cblack;,c107107107,cblack;,c107107107,cblack;,cgray;,cblack;,c107107107,cblack;,b,cblack;,c000000127,cblack;,c107107107,cblack;,b,cblack;,c107107107,cblack;,c000000127,cblack;,c127000127,cblack;,c107107107,cblack;,c000000127,cblack;,c000000127,c000127000,c127000000,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,c000127000,cblack;,c000127127,cblack;,c107107107,cblack;,b,cblack;,c000000127,cblack;,c127000127,cblack;,c107107107,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,c000000127,c000127000,cblack;,c000000127,cblack;,c000000127,c000127000,cblack;,c107107107,cblack;,c000000127,cblack;,c000000127,cblack;,c107107107,cblack;,c000000127,cblack;,!!' readStream nextChunkText!

WebClientHelp subclass: #WebClientReference
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'WebClient-Help'!

----- Method: WebClientReference class>>bookName (in category 'accessing') -----
bookName
        ^'Reference'!

----- Method: WebClientReference class>>builder (in category 'accessing') -----
builder
        ^PackageAPIHelpBuilder!

----- Method: WebClientReference class>>packages (in category 'accessing') -----
packages
        ^#('WebClient-Core')!

CustomHelp subclass: #WebServerHelp
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'WebClient-Help'!

----- Method: WebServerHelp class>>addingActions (in category 'pages') -----
addingActions
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #addingActions"
        ^HelpTopic
                title: 'Adding Actions'
                contents:
'Let''s add some real stuff that might be useful on a server:

        WebServer default addService: ''/smalltalk'' action:[:req| | action |
                action := (req fields at: ''get'' ifAbsent:['''']) asSymbol.
                req send200Response: (Smalltalk perform: action) asString
        ].

We can now request some interesting things like:

        (WebClient httpGet:''http://localhost:8080/smalltalk?get=systemInformationString'') content.
        (WebClient httpGet:''http://localhost:8080/smalltalk?get=platformName'') content.
       
Obviously, this poses quite a risk for abuse. One way to limit this risk is to expose specific actions, such as here:

        #(systemInformationString platformName) do:[:symbol|
                WebServer default addService: ''/info/'', symbol action:[:req|
                        req send200Response: (Smalltalk perform: symbol) asString]].

        (WebClient httpGet:''http://localhost:8080/info/systemInformationString'') content.
        (WebClient httpGet:''http://localhost:8080/info/platformName'') content.

Alternatively, authentication can be used to limit access to exposed resources.
!!
]style[(61 11 7 1 11 1 12 1 7 2 3 1 1 1 1 6 1 1 3 6 1 2 1 1 3 1 6 1 3 1 5 1 9 4 1 1 8 4 3 1 16 1 1 10 8 1 6 1 1 8 5 51 12 8 61 2 7 14 8 50 2 7 2 121 3 23 1 12 2 3 2 6 1 13 7 1 11 1 8 1 1 6 1 7 1 1 3 1 4 3 1 16 1 1 10 8 1 6 1 1 8 1 3 1 12 8 52 2 7 14 8 41 2 7 2 82),cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,b,cblack;,c000127000,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,c127000127,c000127000,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000127000,cblack;,c000000127,cblack;,cgray;,c000127000,cblack;,c000000127,cblack;,,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,c000000127,cblack;,c000000127,cblack;,c000000127,c000127000,cblack;,c000000127,cgray;,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,c127000127,cblack;,c000000127,c000127000,cblack;,,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,!!' readStream nextChunkText!

----- Method: WebServerHelp class>>addingServices (in category 'pages') -----
addingServices
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #addingServices"
        ^HelpTopic
                title: 'Adding Services'
                contents:
'Once the server is running, you can point your browser to http://localhost:8080 but since we haven''t told WebServer what we''d like to do all we get is a 404 (not found) response. To tell WebServer what to do we need to register a service:

        WebServer default addService: ''/hello'' action:[:req|
                req send200Response: ''Hello World''.
        ].

The service takes a path (/hello) and an action to perform for any request that maps to this path. We can now fetch the response in a browser by going to http://localhost:8080/hello or directly using WebClient:

        (WebClient httpGet:''http://localhost:8080/hello'') content.
        (WebClient httpGet:''http://localhost:8080/hello/squeak'') content.
!!
]style[(240 11 7 1 11 1 8 1 7 2 3 1 3 3 1 16 1 13 6 213 12 8 29 2 7 14 8 36 2 7 2),cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;!!' readStream nextChunkText!

----- Method: WebServerHelp class>>authentication (in category 'pages') -----
authentication
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #authentication"
        ^HelpTopic
                title: 'Authentication'
                contents:
'To add authentication you can use web server as follows:

        WebServer default addService: ''/smalltalk'' action:[:req| | action |
                WebServer default authenticate: req realm: ''squeak'' methods: #(digest basic) do:[
                        action := (req fields at: ''get'' ifAbsent:['''']) asSymbol.
                        req send200Response: (Smalltalk perform: action) asString.
                ].
        ].

The above supports both digest as well as basic authentication for accessing the /smalltalk service. Let''s add a user so that we can access it:

        WebServer default passwordAt: ''squeak'' realm: ''squeak'' put: ''squeak''.

The server does NOT store plain text passwords, but rather hashes. To be precise, it stores the ha1 term used in digest authentication which is the same hash produced by htdigest. We can now access the /smalltalk service by providing user name ''squeak'' and password ''squeak''.

        (WebClient httpGet:''http://localhost:8080/smalltalk?get=platformName'') content.

Unfortunately, digest authentication can be slow since our MD5 implementation is rather pathetic.
!!
]style[(58 11 7 1 11 1 12 1 7 2 3 1 1 1 1 6 1 1 13 7 1 13 1 3 1 6 1 8 1 8 3 6 1 5 2 3 1 4 6 1 2 1 1 3 1 6 1 3 1 5 1 9 1 2 1 1 1 8 5 3 1 16 1 1 10 8 1 6 1 1 8 4 1 6 146 11 7 1 11 1 8 1 6 1 8 1 4 1 8 2 278 12 8 50 2 7 2 100),cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,c000127000,cblack;,cgray;,cblack;,b,cblack;,c127000127,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,c127000000,c127000127,c127000000,c127000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,cgray;,c127000127,cblack;,c000000127,cblack;,c000127000,cblack;,,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,!!' readStream nextChunkText!

----- Method: WebServerHelp class>>bookName (in category 'accessing') -----
bookName
        "Returns the name of the custom help book"

        ^'WebServer'!

----- Method: WebServerHelp class>>changeLog (in category 'pages') -----
changeLog
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #changeLog"
        ^HelpTopic
                title: 'Versions'
                contents:
'WebServer 1.4:
* Fixes cookie handling to be in line with RFC 2109
* Support for responses using chunked transfer-encoding

WebServer 1.3:
* Added logging in common log format
* Added support for SSL/TLS via SqueakSSL.

WebServer 1.2:
* Added support for multipart/form-data posts
* Added WebSocket support

WebServer 1.1:
* Added support for specific request methods
* Implement HEAD, TRACE, and OPTIONS in WebServer

WebServer 1.0:
* Initial release.
!!' readStream nextChunkText!

----- Method: WebServerHelp class>>cookies (in category 'pages') -----
cookies
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #cookies"
        ^HelpTopic
                title: 'Cookies'
                contents:
'Because of the performance issues with authentication, we''d like to avoid authentication for each request and instead authenticate once and use some persistent session state (cookies). So let''s do that:

        WebServer default addService: ''/smalltalk'' action:[:req| | session |
                session := WebServer default sessionAt: (req cookieAt: ''session'').
                session ifNil:[ "no session, reguire login"
                        req send302Response: ''/login?url='', req rawUrl encodeForHTTP.
                ] ifNotNil:[ | target action |
                        action := (req fields at: ''get'' ifAbsent:['''']) asSymbol.
                        req send200Response: (Smalltalk perform: action) asString.
                ].
        ].

And of course we now need a login service The service will require authentication and provide a session identifier for the client. It then redirects back to where the request was originally made from:

        WebServer default addService: ''/login'' action:[:req| | session |
                WebServer default authenticate: req realm: ''squeak'' methods: #(digest) do:[ | id |
                        "We have no session state for now, just remember the session id"
                        WebServer default sessionAt: (id := UUID new hex) put: ''''.
                        "Send a redirect back to where we came from with a cookie"
                        req send302Response: (req fields at: ''url'' ifAbsent:[''/''])
                                do:[:reply| reply setCookie: ''session'' value: id path: ''/smalltalk'']]].
!!
]style[(204 11 7 1 11 1 12 1 7 2 3 1 1 1 1 7 1 1 3 7 1 2 11 7 1 10 1 1 3 1 9 1 9 1 4 7 1 6 1 1 27 4 3 1 16 1 13 1 1 3 1 6 1 13 4 1 1 9 1 1 1 1 6 1 6 1 1 4 6 1 2 1 1 3 1 6 1 3 1 5 1 9 1 2 1 1 1 8 5 3 1 16 1 1 10 8 1 6 1 1 8 4 1 6 203 11 7 1 11 1 8 1 7 2 3 1 1 1 1 7 1 1 13 7 1 13 1 3 1 6 1 8 1 8 3 6 2 3 1 1 1 1 2 1 1 4 64 14 7 1 10 1 1 2 1 2 6 3 1 3 1 1 4 1 2 5 58 4 3 1 16 1 1 3 1 6 1 3 1 5 1 9 1 3 1 1 6 3 1 1 5 1 1 5 1 10 1 9 1 6 1 2 1 5 1 13 1 3),cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,b,cblack;,c000000127,cblack;,c000000127,cblack;,c000127000,c000000127,cblack;,c000000127,cblack;,c127000127,c000127000,cblack;,cgray;,cblack;,c000000127,c000127000,cblack;,c000127127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000127000,cblack;,c000000127,c000127000,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,b,cblack;,c127000127,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,c127000000,c127000127,c127000000,c127000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,cgray;,c127000127,cblack;,c000000127,cblack;,c000127000,cblack;,,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,c000127000,cblack;,cgray;,cblack;,cgray;,cblack;,cgray;,cblack;,c000127127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cgray;,cblack;,b,cblack;,c000000127,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000127127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,c127000000,c127000127,c127000000,c127000127,cblack;,c000000127,c127000127,cblack;,c000000127,cgray;,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,cgray;,cblack;,c000000127,cblack;,c127000127,c000127000,cblack;!!' readStream nextChunkText!

----- Method: WebServerHelp class>>errorHandling (in category 'pages') -----
errorHandling
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #errorHandling"
        ^HelpTopic
                title: 'Error Handling'
                contents:
'By default WebServer will send a 500 response with a full debug stack when an error occurs. This may not be appropriate in production environments and consequently, the error handler can be customized. Typically, the error handler will perform one of the following actions:

* Pass the error through. This is useful for debugging, when an error in WebServer should raise a notifier:

        webServer errorHandler:[:err :socket| err pass].

* Send the ''standard'' 500 response (including the full stack): You can simply use WebServer''s default action for this:

        webServer errorHandler:[:err :socket| webServer handleError: err socket: socket.].

* Send a custom 500 response, or perform a redirect, for example:

        webServer errorHandler:[:err :socket|
                [socket sendData:
                        ''HTTP/1.0 302 Temporary redirect'', String crlf,
                        ''Location: /error.html'', String crlf,
                        String crlf.
                socket close] on: Error do:[
                        "Ignore errors in error handling"
                ].
        ].

Of course, you can use any possible combination; including the ability to turn error handling on and off via WebServer http requests.!!
]style[(384 11 13 2 3 2 6 1 1 3 1 4 2 123 10 13 2 3 2 6 1 11 12 1 3 1 7 1 6 3 69 11 13 2 3 2 6 1 3 1 6 1 9 4 33 1 8 5 4 23 1 8 5 11 4 4 6 1 5 1 1 3 7 3 1 4 33 3 1 5 135),cblack;,c000000126,cblack;,c000000126,cblack;,c000000126,cgray;,cblack;,c000000126,cblack;,c000000126,cblack;,,cblack;,c000000126,cblack;,c000000126,cblack;,c000000126,cgray;,cblack;,c000000126,cblack;,c000000126,cblack;,c000000126,cblack;,c000000126,cblack;,,cblack;,c000000126,cblack;,c000000126,cblack;,c000000126,cgray;,cblack;,c000126000,c000000126,cblack;,c000000126,cblack;,c126000126,c000000126,cblack;,c000000126,cblack;,c126000126,c000000126,cblack;,c000000126,cblack;,c000000126,cblack;,c000000126,cblack;,c000000126,c000126000,cblack;,c000000126,cblack;,c000000126,c000126000,cblack;,c000126126,cblack;,c000126000,cblack;,!!' readStream nextChunkText!

----- Method: WebServerHelp class>>introduction (in category 'pages') -----
introduction
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #introduction"
        ^HelpTopic
                title: 'Introduction'
                contents:
'WebServer is a simple, yet reasonably complete HTTP server implementation. WebServer supports streaming, authentication, cookies, and session handling in a compact and easy to use form.

The primary goal for WebServer is for command-and-control style interfaces. If you would like to add some web-based remote control facility without much fuzz and html goodness around it, WebServer is for you.

WebServer comes together with WebClient which provides a similarly complete and simple HTTP client implementation.!!' readStream nextChunkText!

----- Method: WebServerHelp class>>logging (in category 'pages') -----
logging
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #logging"
        ^HelpTopic
                title: 'Logging'
                contents:
'WebServer supports logging in common log format. In order to tell WebServer where to log to you can either give it a stream:

        WebServer default accessLog: Transcript.

or alternatively a file name, for example:

        WebServer default accessLog: ''/var/log/wsd/access_log''.

When used in the latter form, WebServer opens and closes the file for each log entry which provides additional robustness at the cost of some performance.
!!
]style[(126 11 7 1 10 12 46 11 7 1 10 1 25 1 157),cblack;,c000000127,cblack;,c000000127,cblack;,,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,!!' readStream nextChunkText!

----- Method: WebServerHelp class>>pages (in category 'accessing') -----
pages
        "Returns a collection of method selectors to return the pages of the custom help book"
               
        ^#(introduction startingWebServer addingServices serviceHierarchies errorHandling addingActions authentication cookies summary logging sslSupport changeLog)!

----- Method: WebServerHelp class>>serviceHierarchies (in category 'pages') -----
serviceHierarchies
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #serviceHierarchies"
        ^HelpTopic
                title: 'Service Hierarchies'
                contents:
'More specific services are preferred over more general services.  In addition to the /hello service, we can provide a handler for /hello/squeak by adding the following service:

        WebServer default addService: ''/hello/squeak'' action:[:req|
                req send200Response: ''Hello to you too, Squeak!!!!''.
        ].

        (WebClient httpGet:''http://localhost:8080/hello'') content.
        (WebClient httpGet:''http://localhost:8080/hello/squeak'') content.

A default handler for any kind of request can installed by using the ''/'' path:

        WebServer default addService: ''/'' action:[:req|
                req send302Response: ''/hello''. "temporary redirect"
        ].

This will make any request that isn''t handled by an explicit action redirect to /hello where it will be handled by the handler established earlier, for example:

        (WebClient httpGet:''http://localhost:8080/foobar'') content.
!!
]style[(178 11 7 1 11 1 15 1 7 2 3 1 3 3 1 16 1 27 6 1 12 8 29 2 7 14 8 36 2 7 2 81 11 7 1 11 1 3 1 7 2 3 1 3 3 1 16 1 8 2 20 5 163 12 8 30 2 7 1 1),cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c000000127,cgray;,cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000127127,cblack;,,cblack;,c000000127,c127000127,cblack;,c000000127,cblack;,!!' readStream nextChunkText!

----- Method: WebServerHelp class>>sslSupport (in category 'pages') -----
sslSupport
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #sslSupport"
        ^HelpTopic
                title: 'SSL/TLS Support'
                contents:
'WebServer supports secure connections over SSL/TLS via SqueakSSL. To install SqueakSSL, execute the following:

        (Installer ss project: ''SqueakSSL'')
                install: ''SqueakSSL-Core'';
                install: ''SqueakSSL-Tests''.

If you have SqueakSSL installed, you can tell WebServer to use a particular cert which puts WebServer into secure mode.

The certName itself is platform dependent. On Unix, the cert name is the path to the .pem file with BOTH the cert and the private key, for example:

        WebServer default certName: ''/home/user/certs/testcert.pem''.

On Windows, the cert name is a string that is matched against the certificate subject. Usually, the certificate subject includes your host name so that you would use:

        WebServer default certName: ''secure.domain.com''.

Client certificate handling is currently not supported. !!
]style[(112 12 2 1 8 1 11 4 8 1 16 4 8 1 17 1 272 11 7 1 9 1 31 1 170 11 7 1 9 1 19 1 58),cblack;,c000000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,c127000127,cblack;,,cblack;,c000000125,cblack;,c000000125,cblack;,c125000125,cblack;,,cblack;,c000000125,cblack;,c000000125,cblack;,c125000125,cblack;,!!' readStream nextChunkText!

----- Method: WebServerHelp class>>startingWebServer (in category 'pages') -----
startingWebServer
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #startingWebServer"
        ^HelpTopic
                title: 'Starting WebServer'
                contents:
'A WebServer is started by listening on a particular port. The examples below use ''WebServer reset default'' for convenience; specific applications should have their own registry for accessing various WebServer instances.

        (WebServer reset default)
                listenOn: 8080.

The server will persist when the image is restarted and must be stopped explicitly by sending it the #destroy message.
!!
]style[(221 12 5 1 7 4 9 1 4 2 120),cblack;,c000000127,cblack;,c000000127,cblack;,c000000127,cblack;,c127000000,cblack;,!!' readStream nextChunkText!

----- Method: WebServerHelp class>>summary (in category 'pages') -----
summary
        "This method was automatically generated. Edit it using:"
        "WebServerHelp edit: #summary"
        ^HelpTopic
                title: 'Summary'
                contents:
'At this point, making a request like the following:

        (WebClient httpGet: ''http://localhost:8080/smalltalk?get=platformName'') content.

requires several roundtrips:

        1) The first GET request is redirected from /smalltalk to /login
        2) The request to /login is responded to with an authentication challenge
        3) The request to /login is authenticated and a session cookie is established
        4) The request is redirected back to /smalltalk where it is finally handled.

More examples for using WebServer can be found in class WebServer itself. Here is an overview:

        * exampleDoIt - the simplest possible RPC interface to Squeak.
        * exampleBrowse - browse the files on your local disk
        * exampleSession - a simple session example
        * exampleAuth - a simple authentication example
!!
]style[(53 12 8 1 50 2 7 2 639),cblack;,c000000127,cblack;,c127000127,cblack;,c000000127,cblack;,!!' readStream nextChunkText!

WebServerHelp subclass: #WebServerReference
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'WebClient-Help'!

----- Method: WebServerReference class>>bookName (in category 'accessing') -----
bookName
        ^'Reference'!

----- Method: WebServerReference class>>builder (in category 'accessing') -----
builder
        ^PackageAPIHelpBuilder!

----- Method: WebServerReference class>>packages (in category 'accessing') -----
packages
        ^#('WebClient-Core')!