From VisualWorks®, 7.6 of February 1, 2008 on February 1, 2008 at 12:33:51 pm (Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned. Choose terminate or close.'] <class> <name>BodyWriteStream</name> <environment>Net</environment> <super>Net.MessageStream</super> <private>true</private> none buffer <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.BodyWriteStream
The purpose of this stream is to replace the chunked write stream in the case the user wants to avoid chunking (see #doNotChunk). We still need to buffer the contents to compute the correct Content-Length value. Instance Variables: buffer <ReadWriteStream on: ByteArray> internal stream to buffer the contents
</comment> <class> <name>CookieValueWithParams</name> <environment>Net</environment> <super>Net.ValueWithParams</super> <private>false</private> none setSelectors printSelectors <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.CookieValueWithParams
CookieValueWithParams is super class for cookie value. Implements cookie field parsing and printing. Instance Variables: printSelectors <Dictionary> print selectors for cookie field parameters setSelectors <Dictionary> set selectors for cookie field parameters
</comment> <class> <name>AuthenticationPolicy</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none user useProxy rejected authentication authOrder authOrder <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AuthenticationPolicy
AuthenticationPolicy handles different types of authentication for Http messages. The policy will select supported authentication scheme from the server challenge, create an instance of the specific authentication and add an authorization field to a request. The policy will try to handle the server challenge if - a user name and password is provided - the server challenge includes supported authentication scheme Currently supported authentication schemes: Basic, Digest and NTLM. The client side preferences for authetication mechanism are controlled by the authentication order (#authOrder), which can be specified either at the global level (class side) or at the individual instance level. Instance Variables: authOrder <OrderedCollection of HttpAuthentication> authOrder defines supported authentication schemes and order to select a scheme to authorize a message. authentication <HttpAuthentication> authentication instance to authorize a message rejected <Collection of HttpAuthentication> collection of schemes a server rejected to accept. The authentication policy will make an attempt to use another auth scheme from the server challenge list if the first one failed. If the rejected list and the same as the challenge list the auth policy passes the exception. useProxy <Boolean> flag to specify what header field to use: 'authorization' or 'proxy-authorization' user <HttpUser> the user that holds user name, password and collection of realms where this authentication token is valid Class Instance Variables: authOrder <OrderedCollection of HttpAuthentication> authOrder. Default order is #(NTLMAuthentication DigestAuthentication BasicAuthentication) Samples how to use AuthenticationPolicy. More samples can be found in HttpAuthPolicyTest class (HTTPTests package). To run tests see the NetClientsSupportInternal bundle comments. 1. request := HttpRequest readFrom: 'GET http://www.cincomx.com/en/index.asp HTTP/1.1 Host: www.cincom.com:4545 Connection: Keep-Alive' readStream. reply := HttpResponse readFrom: 'HTTP/1.1 401 Unauthorized WWW-Authenticate: Negotiate WWW-Authenticate: NTLM WWW-Authenticate: Basic realm="testrealm@host.com"' readStream. polBuilder := AuthenticationPolicy new. polBuilder policiesOrder: (Array with: BasicAuthentication with: DigestAuthentication with: NTLMAuthentication). polBuilder username: 'aUser' password: 'password'. polBuilder acceptChallenge: reply request: request. polBuilder addAuthorizationTo: request. 2. cl := HttpClient new. cl username: 'winUsername' password: 'winPass'. reply := cl get: html. 3. cl := HttpClient new. cl username: 'winUsername' password: 'winPass'. cl useBasicAuth. reply := cl get: html 4. cl := HttpClient new. [reply := cl get: html. ] on: Net.HttpUnauthorizedError do: [ :ex | cl username: 'winUsername' password: 'winPass'. ex retry] 5. proxy := (HostSpec new name: 'ntlmAuthProxyServer'; type: 'http'; yourself). proxy netUser: (NetUser username: 'winUsername' password: 'winPass'). cl := HttpClient new. cl proxyHost: proxy; useProxy: true. reply := cl get: 'http://www.yahoo.com/'.
</comment> <class> <name>CookieFields</name> <environment>Net</environment> <super>Net.ValueWithParametersField</super> <private>false</private> none <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.CookieFields
CookieFields is super class for 'Cookie', 'Set-Cookie' and 'Set-Cookie2' header fields.
</comment> <class> <name>SetCookieField</name> <environment>Net</environment> <super>Net.CookieFields</super> <private>false</private> none <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.SetCookieField
SetCookieField represents 'Set-Cookie' field. Implementation is based on RFC2965 and Netscape specification. The field value is collection of SetCookieValue.
</comment> <class> <name>SetCookie2Field</name> <environment>Net</environment> <super>Net.SetCookieField</super> <private>false</private> none <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.SetCookie2Field
SetCookie2Field represents 'Set-Cookie2' field. Implementation is based on RFC2965. The field value is collection of SetCookie2Value.
</comment> <class> <name>HttpWriteHandler</name> <environment>Net</environment> <super>Net.MimeWriteHandler</super> <private>false</private> none useGZipTransfer chunkSize shouldChunk useGZipTransfer shouldChunk <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpWriteHandler
This is the writer for HTTP messages. It allows to use compression for message transfer (#useGZipTransfer flag, false by default). It also allows to write messages in a simple continious form with content-length header field specifying the actual message body size in bytes, or in a "chunked" form splitting the body in a number of pieces which doesn't require knowing the full body size upfront (and therefore doesn't include the content-length header). In chunked form the message body is terminated with an "empty" chunk instead. Messages are chunked by default, but this behavior can be controlled using the #shouldChunk option in the following way: If #shouldChunk is true (default) - if message body size exceeds the size specified by the #chunkSize option (#defaultChunkSize is set to 4K), the message will be chunked - if message body size has fewer bytes than the specified #chunkSize, the messages will not be chunked and will use the content-length header instead If #shouldChunk is false - the message will not be chunked regardless of body size and will use the content-length header instead. Note that, when #shouldChunk is false, the writer needs to be able to determine the exact, *final* byte size of the message body (i.e. if the body is to be compressed it has to be the compressed size). The size has to be known before it starts writing the body, so that it can inject the correct content-length field into the header. In general in this mode the body is first written into an internal stream to determine the correct byte count, then the header is finished with the right content-length and finally the body bytes are copied from the internal stream. As an optimization, if the body is simple (i.e. not multi-part) and the size of the body is known upfront, the writer will use that body size for the content-length field and then write the body bytes to the outging stream directly. This doesn't change the behavior in any way, it just may be useful to know that this particular case is handled in more efficient manner than the other non-chunked cases. Instance Variables: useGZipTransfer <Boolean> defines whether or not to transfer a message in gzip format. Adds gzip to the transfer-encoding field chunkSize <Integer> if the mesage body reaches this size we will automatically start "chunking" the body shouldChunk <Boolean> to switch the automatic body chunking on and off Class Instance Variables: useGZipTransfer <Boolean> default value for message transfer compression shouldChunk <Boolean> default value for a message chunking Examples: 1. Writing a message with contens-length field. Message body size doesn't exceeds the default #chunkSize (request := HttpRequest post: 'http://localhost:4461/') contents: HttpWriteHandler xmlDefinition. stream := ((ByteArray new: 100) withEncoding: #ISO8859_1) readWriteStream lineEndCRLF. HttpWriteHandler write: request on: stream. stream reset; contents. 2. Writing a message in chunked format. contents := (Filename fromComponents: ('$(VISUALWORKS)/net/HTTP.pcl' tokensBasedOn: $/)) asFilename contentsOfEntireFile. (request := HttpRequest post: 'http://localhost:4461/') contents: contents; charset: 'utf-8'. stream := ((ByteArray new: 1024) withEncoding: #ISO8859_1) readWriteStream lineEndCRLF. HttpWriteHandler write: request on: stream. stream reset; contents. 3. Writing a message with "Content-length:" field. (request := HttpRequest post: 'http://localhost:4461/') contents: contents; charset: 'utf-8'. stream := ((ByteArray new: 1024) withEncoding: #ISO8859_1) readWriteStream lineEndCRLF. HttpWriteHandler new doNotChunk; writeMessage: request on: stream. stream reset; contents. 4. Writing a message in gzipped and chunked format (request := HttpRequest post: 'http://localhost:4461/') contents: contents; charset: 'utf-8'. stream := ((ByteArray new: 1024) withEncoding: #ISO8859_1) readWriteStream lineEndCRLF. HttpWriteHandler new useGZipTransfer: true; writeMessage: request on: stream. stream reset; contents. 5. Writing a message with specified chunked size (request := HttpRequest post: 'http://localhost:4461/') contents: contents; charset: 'utf-8'. stream := ((ByteArray new: 1024) withEncoding: #ISO8859_1) readWriteStream lineEndCRLF. HttpWriteHandler new chunkSize: 10; writeMessage: request on: stream. stream reset; contents. 6. Writing a message in gzipped format with "Contents-length" (request := HttpRequest post: 'http://localhost:4461/') contents: contents; charset: 'utf-8'. stream := ((ByteArray new: 1024) withEncoding: #ISO8859_1) readWriteStream lineEndCRLF. HttpWriteHandler new doNotChunk; useGZipTransfer: true; writeMessage: request on: stream. stream reset; contents.
</comment> <class> <name>Cookie2Field</name> <environment>Net</environment> <super>Net.StructuredHeaderField</super> <private>false</private> none <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.Cookie2Field
Cookie2Field represents 'cookie2' Http header field. The field is described in RFC2965 and facilitate interoperation between clients and servers that understand different versions of the cookie specification. "Cookie2:" cookie-version
</comment> <class> <name>HttpParser</name> <environment>Net</environment> <super>Net.MimeParser</super> <private>false</private> none <imports> private OS.IOConstants.* </imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpParser
This class is parser for HTTP messages. It's knows how to parse chunked HTTP message bodies, the first line of the Http message and messages with gzipped contents. To be able to read a message and parse it at the same time the parser creates a few layers of streams that wrap an underlaying stream. A possible stack of streams can include the layers in the following order: - to parse an internal stream it is wrapped in to DecodedStream - a chunked message stream is wrapped in to ChunkedStream - then the message stream is wrapped in to BodyStream which reads the number of bytes as it is specified by the message contents length - if the message transfer encoding indicates that compression (gzip) was applied the stream is wrapped in to OS.ZLib.GZipReadStream - the multipart message stream is wrapped in to BoundedStream Instance Variables: readBoundary <String> a multipart message boundary atEnd < Boolean> indicates whether or not the last part of a multipart message has being parsed
</comment> <class> <name>SetCookieValue</name> <environment>Net</environment> <super>Net.CookieValueWithParams</super> <private>false</private> none <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.SetCookieValue
SetCookieValue represents value of 'Set-Cookie2' header field. Implementation supports RFC2109 and Netscape specification The Netscape syntax is Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure The syntax for the Set-Cookie response header is set-cookie = "Set-Cookie:" cookies cookies = 1#cookie cookie = NAME "=" VALUE *(";" set-cookie-av) NAME = attr VALUE = value set-cookie-av = "Comment" "=" value | "Discard" | "Domain" "=" value | "Max-Age" "=" value | "Path" "=" value | "Secure" | "Version" "=" 1*DIGIT
</comment> <class> <name>SetCookie2Value</name> <environment>Net</environment> <super>Net.SetCookieValue</super> <private>false</private> none <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.SetCookie2Value
SetCookie2Value represents value of 'Set-Cookie2' header field. The syntax for the Set-Cookie2 response header is set-cookie = "Set-Cookie2:" cookies cookies = 1#cookie cookie = NAME "=" VALUE *(";" set-cookie-av) NAME = attr VALUE = value set-cookie-av = "Comment" "=" value | "CommentURL" "=" <"> http_URL <"> | "Discard" | "Domain" "=" value | "Max-Age" "=" value | "Path" "=" value | "Port" [ "=" <"> portlist <"> ] | "Secure" | "Version" "=" 1*DIGIT portlist = 1#portnum portnum = 1*DIGIT
</comment> <class> <name>HttpWriteNotification</name> <environment>Net</environment> <super>Net.NetNotification</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpWriteNotification
This is a super class for notifications raised while writing Http messages.
</comment> <class> <name>ReadyToWriteBody</name> <environment>Net</environment> <super>Net.HttpWriteNotification</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.ReadyToWriteBody
This notification is raised by the BodyWriteStream when it receives the #finish message. The notification provides the size of the stream buffer as the parameter. This allows the write handler to add a "content-lenght" header field before writing the contents of the message into the underlying stream.
</comment> <class> <name>HttpEntity</name> <environment>Net</environment> <super>Net.MimeEntity</super> <private>false</private> none nextNamespaceId useGZipTransfer chunkSize decodeContents decompressContents shouldChunk <imports> OS.ZLib.* </imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpEntity
Represents HttpEntity super class. Supports protocol to parse and compose chunked http entity. API to handle message contens: #byteContents - returns row bytes as ByteArray #contents - retuns decoded message contents based on the message charset as ByteString. If the message was not decompresssed returns row bytes as string. #decompressedContents - returns decompress row bytes if the message includes "Content-Encoding: gzip" header field. The header fields will not be removed and the message contents will not be changed. It will still contain row bytes. #decodedContents - returns decoded message contents based on the message charset encoding. The message contents will not be changed. Options to write message contens: #useGZipTransfer #chunkSize #shouldChunk The 'mandatory extension' category represents implementation of RFC2774 An HTTP Extention Framework Instance Variables: nextNamespaceId <Number> represents two-digit header prefix for extention declaration useGZipTransfer <Boolean> defines whether to transfer a message in gzip format. Adds gzip to the transfer-encoding field chunkSize <Number> specifies at what body size to start chunking the message decodeContents <Booelan> defines whether to decode the message contents decompressContents <Boolean > defines whether to decompress the message contents shouldChunk <Boolean> to switch the automatic body chunking on and off. See HttpWriteHandler for more details about the chunking option
</comment> <class> <name>HttpRequest</name> <environment>Net</environment> <super>Net.HttpEntity</super> <private>false</private> none requestLine <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpRequest
Represent Http request message from client to a server. A request message from a client to a server includes, within the first line of that message, the method to be applied to the resource, the identifier of the resource, and the protocol version in use. The rest of the message is standard MIME entity. The methods in low-level command interface protocol allow to execute the request and get a response. Instance Variables: requestLine <HttpRequstLine> an instance of HttpRequestLine Samples: "To decompress contents of a response with compressed transfer encoding" url := 'http://www.fark.com' asURI. req := HttpRequest get: url. req fieldValueAt: 'Accept-Encoding' put: 'gzip'. req decompressContents: true. resp := req execute. "To send a binary file as a post request, compressed and not chunked" file := (Filename fromComponents: ('$(VISUALWORKS)/net/HTTP.pcl' tokensBasedOn: $/)) asFilename readStream binary. (request := HttpRequest post: 'http://localhost:4461/') byteSource: file. stream := ((ByteArray new: 1024) withEncoding: #ISO8859_1) readWriteStream lineEndCRLF. HttpWriteHandler new doNotChunk; useGZipTransfer: true; writeMessage: request on: stream. stream reset; contents
</comment> <class> <name>HttpAuthentication</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none authChallenge user state pathString authPolicy authValue <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpAuthentication
HttpAuthentication is an abstract class for different authentication schemes. The subclasses must provided implementation for the authorization field value. Subclasses must implement the following messages: authorization setNewAuthorizationValue Instance Variables: authChallenge <AuthenticationValue> the server challenge (authentication field value) authValue <AuthenticationValue> the authorization field value authPolicy <AuthenticationPolicy> authentication policy pathString <String> the request url state <ByteSymbol> the authetication state. Depending on a scheme it can have values: #authorized #isNotAuthorized #authorizationInProgress. user <HttpUser> the http user that is used to authorize the message
</comment> <class> <name>NTLMAuthentication</name> <environment>Net</environment> <super>Net.HttpAuthentication</super> <private>false</private> none domain decodedData flags workstation <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.NTLMAuthentication
NTLMAuthentication creates user credentials based on NTLM Authentication Scheme. See http://davenport.sourceforge.net/ntlm.html NTLM is an authentication protocol used in various Microsoft network protocol implementations and supported by the NTLM Security Support Provider ("NTLMSSP"). Limitations: Doesn't support NTLMv2. Instance Variables: domain <String> domain decodedData <ByteArray> decodedData - NTLM challenge from type 2 message flags <ByteArray> list of features supported by the server and client. workstation <String> workstation
</comment> <class> <name>AcceptHeaderFields</name> <environment>Net</environment> <super>Net.ValueWithParametersField</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AcceptHeaderFields
AcceptHeaderFields is abstract class for "Accept.." header fields.
</comment> <class> <name>AcceptCharsetField</name> <environment>Net</environment> <super>Net.AcceptHeaderFields</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AcceptCharsetField
AcceptCharsetField represents "Accept-Charset" header field as it described in RFC2616. The Accept-Charset request-header field can be used to indicate what character sets are acceptable for the response.
</comment> <class> <name>QuotedPrintRequired</name> <environment>Net</environment> <super>Net.NetNotification</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.QuotedPrintRequired
QuotedPrintRequired exception is raised to notify about printing ports for cookie header fields. The syntax requires quotes around the optional port list even if there is only one port number in the port list
</comment> <class> <name>AuthenticateField</name> <environment>Net</environment> <super>Net.ValueWithParametersField</super> <private>false</private> none scheme <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AuthenticateField
This class represents the structure of the www-authenticate/proxy-authenticate field as it described in RFC2616. This is a parametrized field with a single value followed by parameters, but it does not follow the usual practise of separating the paramters by semicolons. Instead it uses commas, and does not require a comma before the first (realm) parameter. Instance Variables: scheme <String> name of authentication scheme
</comment> <class> <name>HttpUser</name> <environment>Net</environment> <super>Net.NetUser</super> <private>false</private> none realms <imports></imports> <category>Net-Clients</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpUser
HttpUser holds a Http client authentication information Instance Variables: realms <OrderedCollection of String> realms where the user token is accepted. The realm value in combination with the canonical root URL of the server being accessed, defines the protection space.
</comment> <class> <name>HttpException</name> <environment>Net</environment> <super>Net.NetError</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpException
This class reports errors which are reported by the HTTP server being accessed. Shared Class Variables: Preferences <OrderedCollection of Association > list of Http errors with description
</comment> <class> <name>HttpClientError</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpClientError
This class reports http client errors which are reported by the HTTP server being accessed. 4xx: Client Error - The request contains bad syntax or cannot be fulfilled Instance Variables:
</comment> <class> <name>HttpUnauthorizedError</name> <environment>Net</environment> <super>Net.HttpClientError</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpUnauthorizedError
This class reports 401 error which are reported by the HTTP server being accessed. "401" ; Unauthorized Instance Variables:
</comment> <class> <name>HttpResponseStatusLine</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none code message protocol version messages <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpResponseStatusLine
Represents the first line of an HttpResponse message that consists of the protocol, version followed by a numeric status code and its associated textual phrase. Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF Instance Variables: code <String> the response code message <String> the code phrase part of the line protocol <String> the protocol part of the line version <String> the version part of the line Class Instance Variables: messages <Dictionary key: String value: String> maps codes to status line messages #code method returns element is a 3-digit integer result code of the attempt to understand and satisfy the request. (Status-Code) #message method is return a short textual description of the code (Reason-Phrase)
</comment> <class> <name>DigestAuthentication</name> <environment>Net</environment> <super>Net.HttpAuthentication</super> <private>false</private> none nonceCount md5SessData defaultAlgorithm defaultAlgorithm <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.DigestAuthentication
DigestAuthentication creates user credentials based on Digest Authentication Scheme (RFC2617). The Digest scheme challenges using a nonce value. A valid response contains a checksum (by default, the MD5 checksum) of the username, the password, the given nonce value, the HTTP method, and the requested URI. Limitations: <qop=auth-int> - option has not been implemented. If the option is used the hash of the entity body has to be calculated. Instance Variables: md5SessData <String> MD5 checksum nonceCount <SmallInteger> description of nonceCount defaultAlgorithm <String> the value can be 'MD5' or 'MD5-sess'. Class Instance Variables: defaultAlgorithm <String> default algorithm (MD5)
</comment> <class> <name>AcceptLanguageField</name> <environment>Net</environment> <super>Net.AcceptHeaderFields</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AcceptLanguageField
AcceptLanguageField represents Accept-Language header field as it described in RFC2616. The Accept-Language request-header field is similar to Accept, but restricts the set of natural languages that are preferred as a response to the request.
</comment> <class> <name>HttpServerError</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpServerError
This class reports server errors which are reported by the HTTP server being accessed. 5xx: Server Error - The server failed to fulfill an apparently valid request Instance Variables:
</comment> <class> <name>HttpAuthenticationExc</name> <environment>Net</environment> <super>Net.HttpClientError</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpAuthenticationExc
HttpAuthenticationExc will be raise if there is no support the challenge scheme received from a server
</comment> <class> <name>CookieValue</name> <environment>Net</environment> <super>Net.CookieValueWithParams</super> <private>false</private> none <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.CookieValue
CookieValue represents value for CookieField class. Supports two specifications RFC2965 and Netscape preliminary specification. The RFC2965 syntax for the header is: cookie = "Cookie:" cookie-version 1*((";" | ",") cookie-value) cookie-value = NAME "=" VALUE [";" path] [";" domain] [";" port] cookie-version = "$Version" "=" value NAME = attr VALUE = value path = "$Path" "=" value domain = "$Domain" "=" value port = "$Port" [ "=" <"> value <"> ] The Netscape syntax is: Cookie: NAME1=OPAQUE_SRTING1; NAME2=OPAQUE_STRING2... Sample how to create cookie fields see in CookieAgent comments
</comment> <class> <name>HttpResponse</name> <environment>Net</environment> <super>Net.HttpEntity</super> <private>false</private> none statusLine <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpResponse
Represents the responce that a server replies after receiving and interpreting a request message. The first line of a HttpResponse message is the status line. Instance Variables: statusLine <HttpStatusLine> an instance of HttpStatusLine
</comment> <class> <name>HttpPrintHandler</name> <environment>Net</environment> <super>Net.MimePrintHandler</super> <private>false</private> none <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpPrintHandler
This class implements printing of HTTP messages on a stream in a shortened (digest) mode to enhance readability of the output.
</comment> <class> <name>AuthenticationValue</name> <environment>Net</environment> <super>Net.HeaderFieldValue</super> <private>false</private> none data realm <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AuthenticationValue
AuthenticationValue parses, composes and holds values for Basic and NTLM authorization and authenication header fields Instance Variables: data <String> authetication data realm <Object> realm identifier (for Basic Authentication)
</comment> <class> <name>HttpDispatcher</name> <environment>Net</environment> <super>Net.MimeDispatcher</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpDispatcher
HttpDispatcher is controlling Http message printing/writing
</comment> <class> <name>HttpProtocolInterpreter</name> <environment>Net</environment> <super>Net.NetProtocolInterpreter</super> <private>false</private> none authPolicy cookieAgent enableCookies request hostName portNumber timeout useProxy proxyHost logAsPrintString chunkSize useGZipTransfer decodeContents decompressContents shouldChunk enableCookieProcessing logAsPrintString <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpProtocolInterpreter
HttpProtocolInterpreter communicates with the Http/Https server via the HttpStreamHandler or HttpsStreamHandler. The HttpProtocolInterpreter creates connection based on URL protocol which can be http or https. Supports cookie state management and authorization. HttpProtocolInterpreter receives server replies or client requests, parses them into the HttpResponse or HttpRequest and handles them where appropriate. Instance Variables: authPolicy <AuthenticationPolicy> will handle the authentication challenge from a server and add user credentials to requests. The client enables cookie managment as soon as it receives the 401/407 exceptions. To validate authorized requests some servers require authorization field and reply cookies. cookieAgent <CookieAgent> provides cookie management enableCookies <Boolean> defines whether or not to enable cookie processing request <HttpRequest> the HttpRequest object hostName <String> the host to connect to portNumber <Number> the host port number timeout <Number> number millisecond to timeout useProxy <Boolean> defines whether or not use proxy connection proxyHost <HostSpec> the proxy server logAsPrintString <Boolean> defines how a request is printed in the Logging Tool. If the option is set to true the message is using #printString for log. If the option is false the message will be written to the log as it send to a socket stream. chunkSize <Number> specifies at what body size to start chunking the message useGZipTransfer <Boolean> defines whether to transfer a message in gzip format. Adds gzip to the transfer-encoding field decodeContents <Booelan> defines whether to decode the message contents decompressContents <Boolean > defines whether to decompress the message contents shouldChunk <Boolean> to switch the automatic body chunking on and off. See HttpWriteHandler for more details about the chunking option Class Instance Variables: enableCookieProcessing <Boolean> default for cookie processing logAsPrintString <Boolean> default for logging messages
</comment> <class> <name>AuthorizationField</name> <environment>Net</environment> <super>Net.AuthenticateField</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AuthorizationField
AuthorizationField represents 'authorization' header field as it described in RFC2616. The client is expected to retry the request, passing an Authorization header line, which is defined according to the server authentication challenge
</comment> <class> <name>TransferEncoding</name> <environment>Net</environment> <super>Net.CollectionField</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.TransferEncoding
TransferEncoding represents transfer encoding field as defines in RFC2616. Value of the field is an ordered collection of string tokens. 14.41 Transfer-Encoding The Transfer-Encoding general-header field indicates what (if any) type of transformation has been applied to the message body in order to safely transfer it between the sender and the recipient. This differs from the content-coding in that the transfer-coding is a property of the message, not of the entity. Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding Transfer-codings are defined in section 3.6. An example is: Transfer-Encoding: chunked If multiple encodings have been applied to an entity, the transfer- codings MUST be listed in the order in which they were applied. Additional information about the encoding parameters MAY be provided by other entity-header fields not defined by this specification. Many older HTTP/1.0 applications do not understand the Transfer- Encoding header.
</comment> <class> <name>AuthenticationInfoField</name> <environment>Net</environment> <super>Net.AuthenticateField</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AuthenticationInfoField
AuthenticationInfoField represents "Authentication-Info" header field as it described in RFC2617. The Authentication-Info header is used by the server to communicate some information regarding the successful digest authentication in the response.
</comment> <class> <name>HttpRedirectionError</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpRedirectionError
This class reports redirection errors which are reported by the HTTP server being accessed. 3xx: Redirection - Further action must be taken in order to complete the request Instance Variables:
</comment> <class> <name>HttpClient</name> <environment>Net</environment> <super>Net.NetClient</super> <private>false</private> none request keepAlive protocol <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpClient
This client makes http/https connections to servers in order to request resources via HTTP protocol, which is a superset of MIME. The HttpClient creates connection based on URL protocol which can be http or https. Supports cookie state management. If the Http client receives the https URL protocol and detects that the HTTPS support is not loaded, the client does the following: 1. if the URL Settings allows to auto load the HTTPS parcel, the parcel will be loaded and and created SSL connection 2. if the URL Settings Https auto load is turned off (default behavior), the HttpClient raises the ComponentNotLoaded exception. The exception is resumable and resuming the exception by default loads the HTTPS parcel. How to send authorized messages see samples in the AuthenticationPolicy class. Instance Variables: request <HttpRequest> the HttpRequest object keepAlive <aBoolean> the variable allows to set persistent connection. protocol <String> 'http' or 'https' based on the protocol will be created an instance of HttpStreamHandler Shared Variables: Protocol <String> 'http' or 'https' Connection connection stream is persistent if #keepAlive method for the HttpClient instance or request returns true connection stream is closed after each request if #keepAlive method for the HttpClient instance and request returns false If server sends a response with closed connection the HttpClient closes the connection stream but doesn't change the #keepAlive variable. Error handling If user application doesn't provide error handling for HttpClient the HttpClient is going to try handle some exceptions by itself. The exceptions that client can handle are located in the HttpProtocolInterpreter processing category. Sample how to create cookie fields see in CookieAgent comments The client will turn on the cookie processing if a server response require authentication.
</comment> <class> <name>ReadyToWriteFirstChunk</name> <environment>Net</environment> <super>Net.HttpWriteNotification</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.ReadyToWriteFirstChunk
The exception is raised when the first chunk of an Http message body is ready to be written to the underlying stream. When the write handler receives the notification it will add a "transfer-encoding: chunked" field to the header and resume writing the message in chunked format.
</comment> <class> <name>ChunkedStream</name> <environment>Net</environment> <super>Net.MessageStream</super> <private>true</private> none buffer <imports> private OS.IOConstants.* </imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.ChunkedStream
ChunkedStream is an abstract class for read write chunked streams. Instance Variables: buffer <ByteArray> buffer holds a chunk of bytes lineEnd <ByteArray> stream line end convention From RFC2616: The chunked encoding modifies the body of a message in order to transfer it as a series of chunks, each with its own size indicator, followed by an OPTIONAL trailer containing entity-header fields. This allows dynamically produced content to be transferred along with the information necessary for the recipient to verify that it has received the full message. Chunked-Body = *chunk last-chunk trailer CRLF chunk = chunk-size [ chunk-extension ] CRLF chunk-data CRLF chunk-size = 1*HEX last-chunk = 1*("0") [ chunk-extension ] CRLF chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) chunk-ext-name = token chunk-ext-val = token | quoted-string chunk-data = chunk-size(OCTET) trailer = *(entity-header CRLF) The chunk-size field is a string of hex digits indicating the size of the chunk. The chunked encoding is ended by any chunk whose size is zero, followed by the trailer, which is terminated by an empty line.
</comment> <class> <name>ChunkedReadStream</name> <environment>Net</environment> <super>Net.ChunkedStream</super> <private>true</private> none <imports> private OS.IOConstants.* </imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.ChunkedReadStream
ChunkedReadStream helps to read chunked messages. Instance Variables:
</comment> <class> <name>BasicAuthentication</name> <environment>Net</environment> <super>Net.HttpAuthentication</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.BasicAuthentication
BasicAuthentication creates user credentials based on Basic Authentication Scheme (RFC2617). The "basic" authentication scheme is based on the model that the client must authenticate itself with a user-ID and a password for each realm. The Basic authentication scheme is not a secure method of user authentication, nor does it in any way protect the entity, which is transmitted in cleartext across the physical network used as the carrier.
</comment> <class> <name>CookieAgent</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none registry cacheCookies useCachedCookies enableLimits <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.CookieAgent
CookieAgent provides cookie management during a session with Http requests and responses. Implementation based on RFC2965 and Netscape preliminary specification (http://wp.netscape.com/newsref/std/cookie_spec.html). Instance Variables: cacheCookies <Boolean> specifies whether or not to cache cookies enableLimits <Boolean> specifies whether or not to check registry limits registry <Dictionary> cookie registry useCachedCookies <Boolean> specifies whether or not to use cached cookie when a session starts Shared variable Registry <Dictionary > holds cached cookies. How to create cookie fields: "Creating Cookies using Netscape style" header := SetCookieValue netscapeStyleName: 'Customer' value: 'WILE_E_COYOTE'. header secure: true; expires: Timestamp now; path: '/smalltalk'; domain: 'cincom.com'. 'Customer=WILE_E_COYOTE;expires=Mon, 31 Jan 2005 19:36:35 GMT;path=/smalltalk;secure;domain=cincom.com' cookie := CookieField newNetscape. cookie addValue: (CookieValue name: 'Customer' value: 'WILE_E_COYOTE'); addValue: ( CookieValue name: 'Part_Number' value: 'Rocket_Launcher_0001'); addValue: ( CookieValue name: 'Shipping' value: 'FedEx'). 'Cookie: Customer=WILE_E_COYOTE;Part_Number=Rocket_Launcher_0001;Shipping=FedEx' "Creating RFC style cookies" cookie := CookieField new. val := cookie addName: 'Customer' value: 'WILE_E_COYOTE'. val path: '\acme'; domain: 'foo.com'; port: 8085. val := cookie addName: 'Part_Number' value: 'Rocket_Launcher_0001'. val path: '\info'; domain: 'foo1.com'. 'Cookie: $version=1; Customer=WILE_E_COYOTE;$path=\acme;$port="8085";$domain=foo.com; Part_Number=Rocket_Launcher_0001;$path=\info;$domain=foo1.com' header := SetCookieValue name: 'Customer' value: 'WILE_E_COYOTE'. header secure: true; domain: 'cincom.com'; maxAge: 0; comment: 'some comments'. 'Customer=WILE_E_COYOTE;max-age=0;comment="some comments";domain=cincom.com;version=1;secure' header := SetCookie2Value name: 'Customer' value: 'WILE_E_COYOTE'. header secure: true; domain: 'cincom.com'; maxAge: 0; comment: 'some comments'; port: (OrderedCollection with: 8080 with: 80). 'Customer=WILE_E_COYOTE;secure;comment="some comments";max-age=0;domain=cincom.com;port="8080,80";version=1'
</comment> <class> <name>HttpStatusLineError</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpStatusLineError
HttpStatusLineError is raised if the Http parser read an empty response status line
</comment> <class> <name>ManOptField</name> <environment>Net</environment> <super>Net.AcceptHeaderFields</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.ManOptField
ManOptField represents a mandatory field. For example: Man: http://www.copyright.org/rights-management; ns=16
</comment> <class> <name>CacheControl</name> <environment>Net</environment> <super>Net.CollectionField</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.CacheControl
CacheControl represents 'cache-control' Http header field. The Cache-Control general-header field is used to specify directives that MUST be obeyed by all caching mechanisms along the request/response chain. Cache-Control = "Cache-Control" ":" 1#cache-directive cache-directive = cache-request-directive | cache-response-directive cache-request-directive = "no-cache" [ "=" <"> 1#field-name <"> ] | "no-store" | "max-age" "=" delta-seconds | "max-stale" [ "=" delta-seconds ] | "min-fresh" "=" delta-seconds | "only-if-cached" | cache-extension cache-response-directive = "public" | "private" [ "=" <"> 1#field-name <"> ] | "no-cache" [ "=" <"> 1#field-name <"> ] | "no-store" | "no-transform" | "must-revalidate" | "proxy-revalidate" | "max-age" "=" delta-seconds | cache-extension no-cache Indicates that all or part of the response message MUST NOT be cached anywhere. This allows an origin server to prevent caching even by caches that have been configured to return stale responses to client requests Note: Most HTTP/1.0 caches will not recognize or obey this directive.
</comment> <class> <name>HttpInformationalError</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpInformationalError
This class reports http informational errors which are reported by the HTTP server being accessed. 1xx: Informational - Request received, continuing process Instance Variables:
</comment> <class> <name>CookieField</name> <environment>Net</environment> <super>Net.CookieFields</super> <private>false</private> none version <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.CookieField
CookieField represents 'Cookie' field. Instance Variables: version <Number> cookie version value <Collection> collection of CookieValue Sample how to create cookie fields see in CookieAgent comments
</comment> <class> <name>HttpSocketAccessor</name> <environment>Net</environment> <super>OS.SocketAccessor</super> <private>false</private> none time timeout <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpSocketAccessor
This class overrides its superclass to allow timeouts on reads, and also to choose a different kind of IOBuffer (indirectly through its choice of ExternalConnection class). Instance Variables: time <Integer> time of the last successful read, in milliseconds timeout <Integer> how long we should wait while reading a buffer, before assuming the connection died.
</comment> <class> <name>HttpConnection</name> <environment>Net</environment> <super>Net.NetConnection</super> <private>false</private> none <imports> private OS.IOConstants.* </imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpConnection
HttpConnection is the HTTP connection stream wrapper
</comment> <class> <name>HttpBadRequest</name> <environment>Net</environment> <super>Net.HttpClientError</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpBadRequest
HttpBadRequest reports 400 Http errors. The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications
</comment> <class> <name>HttpObjectNotFound</name> <environment>Net</environment> <super>Net.HttpClientError</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpObjectNotFound
HttpObjectNotFound reports 404 errors. The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent.
</comment> <class> <name>HttpMovedError</name> <environment>Net</environment> <super>Net.HttpRedirectionError</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpMovedError
This class reports 301/302 errors which are reported by the HTTP server being accessed. "301" ; Moved Permanently "302" ; Moved Temporarily Instance Variables:
</comment> <class> <name>UseChunkingForSingleChunk</name> <environment>Net</environment> <super>Net.HttpWriteNotification</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.UseChunkingForSingleChunk
This notification is raised when a chunked write stream receives the #finish command but no chunks have been written yet. This allows the higher levels to decide if chunking should still be used even for messages shorter than the chosen chunk size. The decision is conveyed by the resumption parameter and the default resumption value is false, i.e. do not use chunking for short messages. The HTTP writer handles this notification by adding "content-length: number" field and resuming without chunking.
</comment> <class> <name>DigestAuthenticationValue</name> <environment>Net</environment> <super>Net.ValueWithParams</super> <private>false</private> none <imports></imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.DigestAuthenticationValue
DigestAuthenticationValue parses, composes and holds values for Digest authorization and authenication header fields
</comment> <class> <name>HttpRequestLine</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none method url version prefix path useProxy <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpRequestLine
Represents the requst line of Http message. Request-Line = Method SP Request-URI SP HTTP-Version CRLF Instance Variables: method <String> the method to be applied to the resource url <URI> the resorce locator version <String> HTTP protocol version to use prefix <String> the request line prefix path <URI> the request line path useProxy <Boolean> defines whether or not the server is proxy
</comment> <class> <name>ChunkedWriteStream</name> <environment>Net</environment> <super>Net.ChunkedStream</super> <private>true</private> none writeLimit useChunks bufferNumber defaultWriteLimit <imports> private OS.IOConstants.* </imports> <category>HTTP</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.ChunkedWriteStream
ChunkedWriteStream helps to read and write chunked messages. The ChunkedStream collects the message body bytes in a buffer until the buffer is filled. The buffer size is settable and the default size is 4K. If the message body fits entirely into a single buffer the message won't be chunked, it will be sent as is and the message header will include the "Content-length" field with corresponding byte size value. If the body is longer than the buffer then when the ChunkedStream is about to write the first chunk into the underlying stream it notifies the higher levels of the framework which will add a "transfer-encoding: chunked" header field instead and the body will be written out in the chunked format. Instance Variables: writeLimit <Number> chunk size useChunks <Boolean> defines whether or not use chunks to write in to the underlying stream. bufferNumber <Number> if the fist buffer is ready to be flushed in to the underlying stream the ChuckedWriteStream raises an exception. The exception is used by the HttpPrinter to add "Transfer-encoding" field to the message
</comment> <class> <name>HttpBuildHandler</name> <environment>Net</environment> <super>Net.MimeParserHandler</super> <private>false</private> none decompressContents decodeContents decompressContents decodeContents <imports> OS.ZLib.* </imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpBuildHandler
This class builds Http messages. Depending on parsing option the builder writes raw socket bytes in to the message body or decompressed and decoded string. See the option description in the HttpClient class comments. The builder allows to deal with large attachments by saving them directly into files. Instance Variables: decompressContents <Boolean> should we decompress message contents if it is compressed decodeContents <Boolean> should we decode message contents into characters Class Instance Variables: decompressContents <Boolean> should we decompress message contents if it is compressed decodeContents <Boolean> should we decode message contents into characters Samples 1. Creating a request or response entity httpEntity := HttpBuildHandler readFrom: stream. 2. Creating an http entity with header parsed only builder := HttpBuildHandler on: stream. request := builder readHeader. "Parsing the message body" builder readBody. 3. Saving an attachment with the specified file name filename := HttpBuildHandler defaultAttachmentDirectory, 'temp.txt'. client := HttpClient new. [[response2 := client executeRequest: request.] on: AttachmentFilename do: [ :ex | ex resume: filename ]. ] ensure: [ client close ] ]. 4. Writing a message with specified chunk size response := HttpResponse code: '200'. response contents: 'some text'. response addFileAttachment: someAttachmentFile. response newWriter chunkSize: 25; writeMessage: response on: stream. 5. Writing a message in GZip format. response := HttpResponse code: '200'. response contents: 'some text'. response newWriter useGZipTransfer: true; writeMessage: response on: stream.
</comment> <class> <name>HttpTimeout</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpTimeout
Timeout exception is raised after the time we wait while reading a buffer in HttpSockedAccessor is expired. Instance Variables:
</comment> <class> <name>RegistryLimitationExc</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.RegistryLimitationExc
RegistryLimitationExc exception is raised when one of the registry limits was exceeded
</comment> <class> <name>HttpProxyAuthenticationError</name> <environment>Net</environment> <super>Net.HttpClientError</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpProxyAuthenticationError
This class reports 407 error which are reported by the HTTP server being accessed. "407" ; Proxy Authentication Required Instance Variables:
</comment> <class> <name>HttpURL</name> <environment>Net</environment> <super>OS.URLwithAuthority</super> <private>false</private> none user decompressContents decodeContents <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpURL
This URL describes resources accessed using the HTTP protocol. Instance Variables: user <NetUser> an user ID authorized to access the proxy server decompressContents <Boolean> defines whether or not to decompess the reponse contents decodeContents <Boolean> defines whether or not to decode the response contents
</comment> <class> <name>UnknownCookieParameter</name> <environment>Net</environment> <super>Net.NetError</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.UnknownCookieParameter
UnknownCookieParameter the exception is raised when unknown parameter is detected while parsing cookie fields.
</comment> <class> <name>AcceptField</name> <environment>Net</environment> <super>Net.AcceptHeaderFields</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.AcceptField
AcceptField represents "Accept" header field as it described in RFC2616. The Accept request-header field can be used to specify certain media types which are acceptable for the response. Accept headers can be used to indicate that the request is specifically limited to a small set of desired types, as in the case of a request for an in-line image.
</comment> <class> <name>HttpNotExtendedError</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpNotExtendedError
HttpNotExtendedError reports 510 errors. The server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource
</comment> <class> <name>HttpEntityError</name> <environment>Net</environment> <super>Net.HttpException</super> <private>false</private> none <imports></imports> <category>Net-HTTP-Support</category> <attributes> <package>HTTP</package> </attributes> </class> <comment> Net.HttpEntityError
This exception is raised if the error was detected while parsing the http entity.
</comment> <name>Protocol</name> <environment>Net.HttpClient</environment> <private>false</private> <constant>false</constant> <category>protocol</category> <attributes> <package>HTTP</package> </attributes> <name>Registry</name> <environment>Net.CookieAgent</environment> <private>false</private> <constant>false</constant> <category>registry</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>NumberEntries</name> <environment>Net.CookieAgent</environment> <private>false</private> <constant>false</constant> <category>registry</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>NumberBytesPerCookie</name> <environment>Net.CookieAgent</environment> <private>false</private> <constant>false</constant> <category>registry</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>ServersCacheCookiesFrom</name> <environment>Net.CookieAgent</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>NumberEntriesPerServer</name> <environment>Net.CookieAgent</environment> <private>false</private> <constant>false</constant> <category>registry</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>EnableLimits</name> <environment>Net.CookieAgent</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>UseCachedCookies</name> <environment>Net.CookieAgent</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>CacheCookies</name> <environment>Net.CookieAgent</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>DefaultVersion</name> <environment>Net.CookieFields</environment> <private>false</private> <constant>false</constant> <category>style</category> <initializer>nil</initializer> <attributes> <package>HTTP</package> </attributes> <name>CookieStyle</name> <environment>Net.CookieValueWithParams</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer></initializer> <attributes> <package>HTTP</package> </attributes> <name>Preferences</name> <environment>Net.HttpException</environment> <private>false</private> <constant>false</constant> <category>preferences</category> <attributes> <package>HTTP</package> </attributes> <methods> Net.BodyWriteStream <category>accessing</category>
buffer ^buffer
flush
nextPut: anObject buffer nextPut: anObject
</methods> <methods> Net.BodyWriteStream <category>initialize-release</category>
initializeOn: aStream stream := aStream. buffer := (ByteArray new: 1024) readWriteStream
</methods> <methods> Net.BodyWriteStream <category>status</category>
finish ReadyToWriteBody raiseRequestWith: buffer position. stream binary. buffer reset. stream nextPutAll: buffer contents. stream flush
</methods> <methods> Net.CookieValueWithParams <category>accessing</category>
addPort: aNumber ^self port: aNumber
domain ^self params at: #domain ifAbsent: [nil]
domain: aString self params at: #domain put: aString
name ^self value key
nameValue ^self value value
path ^self params at: #path ifAbsent: [nil]
path: aString self params at: #path put: aString
port ^self params at: #port ifAbsent: [ nil ]
port: aCollOfNumbersOrNumber | coll | (aCollOfNumbersOrNumber isKindOf: Boolean) ifTrue: [^self params at: #port put: aCollOfNumbersOrNumber]. coll := (aCollOfNumbersOrNumber isKindOf: Collection) ifTrue: [aCollOfNumbersOrNumber] ifFalse: [OrderedCollection with: aCollOfNumbersOrNumber]. ^self params at: #port put: coll
separators separators isNil ifTrue: [separators := SetCookieField defaultSeparators ]. ^separators
version ^self params at: #version ifAbsent: [nil ]
version: aNumber self params at: #version put: aNumber
</methods> <methods> Net.CookieValueWithParams <category>parsing-printing params</category>
portPrintString "The syntax requires quotes around the portlist even if there is only one port in the list " | aStream | ^(self port isKindOf: Boolean) ifTrue: [ nil ] ifFalse: [self port isEmpty ifTrue: [ ^nil]. aStream := String new writeStream. self port do: [ :px | aStream nextPutAll: px printString ] separatedBy: [ aStream nextPut: $, ]. QuotedPrintRequired raiseFrom: aStream contents ]
setPort: aStringOrBoolean | scanner coll | aStringOrBoolean isString ifTrue: [coll := OrderedCollection new. scanner := self scannerOn: aStringOrBoolean readStream. scanner tokenizeList: [coll add: scanner nextToken asNumber ] separatedBy: [ scanner token = $, ]. self params at: #port put: coll ] ifFalse: [ self params at: #port put: aStringOrBoolean ]
setVersion: aString | n | n := aString asNumber. n ~= self defaultVersionNumber ifTrue: [^self error: (#DetectedUnrecognizedCookieVersion << #net >> 'Detected unrecognized cookie version: <1s>' expandMacrosWith: aString ) asString]. self version: n.
versionPrintString "The syntax requires quotes around the portlist even if there is only one port in the list " | aStream | aStream := String new writeStream. aStream nextPutAll: self version printString. ^aStream contents
</methods> <methods> Net.CookieValueWithParams <category>initialize-release</category>
initialize super initialize. setSelectors := Dictionary new. setSelectors at: #version put: #setVersion:; at: #path put: #path:; at: #domain put: #domain:; at: #port put: #setPort:. printSelectors := Dictionary new. printSelectors at: #version put: #versionPrintString; at: #path put: #path; at: #domain put: #domain; at: #port put: #portPrintString.
name: aString value: vString self setValueName: aString value: vString. self setRFCStyle
netscapeStyleName: aString value: vString self setValueName: aString value: vString. self setNetscapeStyle
setValueName: aString value: vString value := Association key: aString value: vString.
</methods> <methods> Net.CookieValueWithParams <category>parsing</category>
addParameterNamed: valString value: parString | sel | (sel := setSelectors at: valString asLowercase asSymbol ifAbsent: [nil]) notNil ifTrue: [self params at: valString asSymbol ifAbsent: [self perform: sel with: parString]] ifFalse: [self processUnknownParam: valString value: parString]
finishParse (self params at: #version ifAbsent: [nil ]) isNil ifTrue: [self setNetscapeStyle] ifFalse: [self setRFCStyle]
parseParamValueFrom: scanner ^(scanner hereChar == $; or: [scanner hereChar isNil ]) ifTrue: ["no value param (secure/discard)" true ] ifFalse: [scanner peek == $" ifTrue: ["RFC style" MimeEncodedWordCoDec decodeText: scanner nextToken] ifFalse: ["possible Netscape style" scanner scanWhile: [ scanner hereChar ~= self parametersSeparator]]]
</methods> <methods> Net.CookieValueWithParams <category>printing</category>
printParameter: name value: anObject on: aStream | printSel printValue | (printSel := printSelectors at: name asSymbol ifAbsent: [nil]) notNil ifTrue: [[printValue := self perform: printSel. self isRFCStyle ifTrue: [super printParameter: name value: printValue on: aStream ] ifFalse: [printValue notNil ifTrue: [aStream nextPutAll: '=', printValue ]] ] on: QuotedPrintRequired do: [ :ex | self printParameterAsQuotedText: name value: ex parameter on: aStream ] ]
printParameterAsQuotedText: name value: anObject on: aStream self class scannerType print: $= on: aStream. [self class scannerType printQuotedText: anObject on: aStream ] on: NonASCIICharacter do: [ :ex | aStream nextPut: $"; nextPutAll: anObject; nextPut: $"]
printValueOn: aStream value ~~ nil ifTrue: [self isRFCStyle ifTrue: [aStream nextPutAll: self value key,'='. self class scannerType printWord: self value value on: aStream] ifFalse: [aStream nextPutAll: self value key,'=',self value value]]
</methods> <methods> Net.CookieValueWithParams <category>cookie style</category>
isNetscapeStyle ^self isRFCStyle not
isRFCStyle ^self version notNil
setNetscapeStyle self removeParamAt: #version.
setRFCStyle self version: self defaultVersionNumber.
</methods> <methods> Net.CookieValueWithParams <category>private-utility</category>
processUnknownParam: valString value: parString self error: (#DetectedUnrecognizedCookieAttribute << #net >> 'Detected unrecognized cookie attribute: <1s>' expandMacrosWith: valString ) asString
tokenizedValueFrom: rfc822Stream "The Name=Value is required and must be the first pair in Set-Cookie field" | nx vx | nx := rfc822Stream upTo: $=. rfc822Stream hereChar = $= ifFalse: [self error: (#WrongNameValueParameter << #net >> 'Wrong required NAME=VALUE parameter ')]. vx := rfc822Stream peek = $" ifTrue: [rfc822Stream nextToken] ifFalse: [rfc822Stream upToEnd]. ^nx -> vx
validateNextToken: scanner for: parName | tok | tok := scanner peek. ^tok == $= ifTrue: [ scanner next. true] ifFalse: [tok = $; or: [tok isNil ]]
</methods> <methods> Net.CookieValueWithParams <category>defaults</category>
defaultVersionNumber "RFC2965: Version=value REQUIRED. The value of the Version attribute, a decimal integer, identifies the version of the state management specification to which the cookie conforms. For this specification, Version=1 applies." ^CookieFields defaultVersion
</methods> <methods> Net.CookieValueWithParams <category>comparing</category>
= aCookieValue | d dv p pv | d := self domain isNil ifTrue: [ nil] ifFalse: [ self domain asLowercase ]. dv := aCookieValue domain isNil ifTrue: [ nil] ifFalse: [ aCookieValue domain asLowercase ]. p := self path isNil ifTrue: [ nil] ifFalse: [ self path asLowercase ]. pv := aCookieValue path isNil ifTrue: [ nil] ifFalse: [ aCookieValue path asLowercase ]. ^self name = aCookieValue name and: [ d = dv and: [ p = pv ] ]
</methods> <methods> Net.CookieValueWithParams class <category>instance creation</category>
name: nString value: vString "Create cookie value field in default RFC style" ^self new name: nString value: vString; yourself
netscapeStyleName: nString value: vString "Create cookie value field in Netscape style" ^self new netscapeStyleName: nString value: vString; yourself
rfcStyleName: nString value: vString "Create cookie value field in RFC style" ^self name: nString value: vString
</methods> <methods> Net.AuthenticationPolicy <category>accept challenge</category>
acceptAuthInfoFrom: aHttpResponse self resetRejected. self authentication ifNotNil: [ self authentication acceptAuthInfoFrom: aHttpResponse ]
acceptChallenge: aHttpResponse ^self acceptChallenge: aHttpResponse request: nil
acceptChallenge: aHttpResponse request: aHttpRequest "1. no user/pass ---- pass exc 2. no authenticate field ----- pass exc 3. authorization is provided but not accepted. a. wrong user/pass b. wrong scheme c. different realm - try another scheme if there is a choice - there is no scheme that accepts the challenge - pass exc - retry for diff. realm if the scheme auth depends on it " | authenticate | "if there is a user name and password provided or challenge in the response" (self canBeAuthorized not or: [(authenticate := self authenticateFieldFrom: aHttpResponse) isNil]) ifTrue: [ ^false]. "some scheme's (NTLM) may require additional replies to complete authorization " (self isAuthorizationInProgress and: [self authentication proceedWith: authenticate ]) ifTrue: [^true]. "the request has being authorized " self isAuthorized ifTrue: [ "check if there is a different realm in the challenge" (self authentication canAccept: authenticate) ifTrue: [ ^true]. "try another scheme if any" ^self tryAnotherAuthFrom: authenticate]. "it has not being authorized yet " ^(authentication := self newPolicyFrom: authenticate) notNil
</methods> <methods> Net.AuthenticationPolicy <category>initialize-release</category>
setNotAuthorizedState self authentication ifNotNil: [ self authentication setNotAuthorizedState ]. self resetRejected
useBasicAuth authentication := BasicAuthentication policy: self
useNTLMAuth authentication := NTLMAuthentication policy: self. authentication authChallenge: AuthenticateField new addNTLM.
user: aHttpUser aHttpUser notNil ifTrue: [user := aHttpUser isHttpUser ifTrue: [aHttpUser ] ifFalse: [ HttpUser username: aHttpUser username password: aHttpUser password]]. self setNotAuthorizedState
username: aString password: pString self username: aString password: pString useProxy: false
username: aString password: pString realm: rString self username: aString password: pString realm: rString useProxy: false
username: aString password: pString realm: rString useProxy: aBoolean (self username ~= aString or: [self password ~= pString ]) ifTrue: [self setNotAuthorizedState]. user := HttpUser username: aString password: pString. user addRealm: rString. useProxy := aBoolean.
username: aString password: pString useProxy: aBoolean self username: aString password: pString realm: nil useProxy: aBoolean
</methods> <methods> Net.AuthenticationPolicy <category>accessing</category>
authentication ^authentication
authentication: anHttpAuthentication authentication := anHttpAuthentication
authOrder ^authOrder ifNil: [ authOrder := self class authOrder ]
authOrder: aCollectionOfHttpAuth authOrder := aCollectionOfHttpAuth
header ^self useProxy ifTrue: ['proxy-authorization'] ifFalse: ['authorization' ]
password ^self user password
realm ^self user realm
realm: aString self user addRealm: aString.
rejected rejected ifNil: [ self resetRejected ]. ^rejected
resetRejected rejected := OrderedCollection new
useProxy ^useProxy ifNil: [ false ]
useProxy: aBoolean useProxy := aBoolean
user ^user ifNil: [ user := HttpUser new]
username ^self user username
</methods> <methods> Net.AuthenticationPolicy <category>testing</category>
canBeAuthorized ^self username notNil and: [ self password notNil]
isAuthorizationInProgress ^self authentication notNil and: [ self authentication isAuthorizationInProgress]
isAuthorized ^self authentication notNil and: [self authentication isAuthorized]
</methods> <methods> Net.AuthenticationPolicy <category>private</category>
authenticateFieldFrom: aHttpResponse | f | (aHttpResponse wwwAuthenticate isEmpty and: [aHttpResponse proxyAuthenticate isEmpty]) ifTrue: [ ^nil]. (f := aHttpResponse wwwAuthenticate) notEmpty ifTrue: [ useProxy := false ] ifFalse: [ (f := aHttpResponse proxyAuthenticate) notEmpty ifTrue: [ useProxy := true ]]. ^f isEmpty ifTrue: [nil] ifFalse: [ f first ].
detectSupportedPolicy: anAuthentication | polCl challenge | polCl := self authOrder detect: [ :scheme | (challenge := anAuthentication value select: [ :val | scheme acceptScheme: val scheme]) notEmpty ] ifNone: [HttpAuthenticationExc raiseRequestWith: anAuthentication errorString: (#ThereIsNoSupportedAuthentication << #net >> 'There is no supported authentication detected in: <1s>' expandMacrosWith: anAuthentication printString)]. ^polCl->challenge
newPolicyFrom: anAuthenticate | policyChallenge | anAuthenticate ifNil: [ ^nil ]. policyChallenge := self detectSupportedPolicy: anAuthenticate. (authentication := policyChallenge key policy: self ) setAuthChallengeFrom: policyChallenge value. ^authentication
tryAnotherAuthFrom: anAuthentication | challenge polClass | self rejected add: self authentication class. self authOrder size = self rejected size ifTrue: [^false]. polClass := self authOrder detect: [ :scheme | (self rejected includes: scheme) not and: [(challenge := anAuthentication value select: [ :val | scheme acceptScheme: val scheme]) notEmpty ]] ifNone: [nil]. polClass isNil ifTrue: [ ^false]. (authentication := polClass policy: self ) setAuthChallengeFrom: challenge. ^authentication notNil
</methods> <methods> Net.AuthenticationPolicy <category>add authorization</category>
addAuthorizationTo: aHttpRequest (self canBeAuthorized not or: [self authentication isNil]) ifTrue: [ ^nil]. aHttpRequest removeFieldAt: self header. self authentication addAuthorizationTo: aHttpRequest for: self header.
</methods> <methods> Net.AuthenticationPolicy class <category>instance creation</category>
username: aString password: pString ^self username: aString password: pString useProxy: false
username: aString password: pString useProxy: aBoolean ^self new username: aString password: pString useProxy: aBoolean; yourself
</methods> <methods> Net.AuthenticationPolicy class <category>accessing</category>
authOrder ^authOrder ifNil: [ authOrder := self defaultAuthOrder ]
authOrder: aCollection authOrder := aCollection
</methods> <methods> Net.AuthenticationPolicy class <category>default values</category>
defaultAuthOrder ^Array with: NTLMAuthentication with: DigestAuthentication with: BasicAuthentication
</methods> <methods> Net.CookieFields <category>initialize-release</category>
addName: nameString value: valString | cookie | cookie := self valueWithParamsClass name: nameString value: valString. self value add: cookie. ^cookie
initialize name := self class fieldNames first
</methods> <methods> Net.CookieFields <category>adding</category>
add: aCookieField self value addAll: aCookieField value
addValue: aCookieValueWithParams self value add: aCookieValueWithParams
</methods> <methods> Net.CookieFields class <category>defaults</category>
defaultSeparators ^#($; $; $, )
defaultVersion ^DefaultVersion isNil ifTrue: [ 1 ] ifFalse: [ DefaultVersion ]
defaultVersion: aNumber DefaultVersion := aNumber
</methods> <methods> Net.SetCookieField <category>accessing</category>
valueWithParamsClass ^SetCookieValue
</methods> <methods> Net.SetCookieField <category>testing</category>
shouldTerminateSession ^(self value detect: [ :vx | vx maxAge = 0 ] ifNone: [nil]) notNil
</methods> <methods> Net.SetCookieField <category>composing</category>
writeOn: aStream encoding: aString self printOn: aStream indent: 0
</methods> <methods> Net.SetCookieField <category>printing</category>
printOn: aStream indent: level self value do: [ :vx | self printNameOn: aStream. vx printOn: aStream] separatedBy: [ aStream cr ]
</methods> <methods> Net.SetCookieField class <category>instance creation</category>
add: aSetCookieValue ^self new add: aSetCookieValue; yourself
addName: nameString value: valString ^self new addName: nameString value: valString; yourself
new ^super new initialize
</methods> <methods> Net.SetCookieField class <category>parsing</category>
fieldNames ^#('set-cookie' )
</methods> <methods> Net.SetCookie2Field <category>accessing</category>
valueWithParamsClass ^SetCookie2Value
</methods> <methods> Net.SetCookie2Field class <category>parsing</category>
fieldNames ^#('set-cookie2' )
</methods> <methods> Net.HttpWriteHandler <category>accessing</category>
chunkSize ^chunkSize
chunkSize: aNumber chunkSize := aNumber. "a nil is a valid input and means use default settings for chunking" aNumber ifNotNil: [ self doChunk ]
doChunk self shouldChunk: true
doNotChunk self shouldChunk: false
shouldChunk ^shouldChunk ifNil: [shouldChunk := self class shouldChunk]
shouldChunk: aBoolean shouldChunk := aBoolean
useGZipTransfer ^useGZipTransfer ifNil: [useGZipTransfer := self class useGZipTransfer]
useGZipTransfer: aBoolean useGZipTransfer := aBoolean
</methods> <methods> Net.HttpWriteHandler <category>action callbacks</category>
endHeader: aMessageHeader aMessageHeader parent isHttpEntity ifFalse: [ self stream cr ]. ^aMessageHeader parent
endMessage: aMessage ^[ super endMessage: aMessage ] on: HttpWriteNotification do: [ :notification | self processMessagePrintNotification: notification message: aMessage ].
processMessageBody: aMessage do: aBlock [super processMessageBody: aMessage do: aBlock] on: HttpWriteNotification do: [ :notification | self processMessagePrintNotification: notification message: aMessage ]
processMessagePrintNotification: notification message: aMessage (ReadyToWriteFirstChunk accepts: notification class) ifTrue: [ self addTransferChunked: notification parameter. notification resume ]. (UseChunkingForSingleChunk accepts: notification class) ifTrue: [ self addContentLength: notification parameter entity: aMessage. notification resume: false ]. (ReadyToWriteBody accepts: notification class) ifTrue: [ self addContentLength: notification parameter entity: aMessage. notification resume ].
</methods> <methods> Net.HttpWriteHandler <category>defaults</category>
defaultEncoding ^HttpConnection defaultEncoding
dispatcherClass ^HttpDispatcher
</methods> <methods> Net.HttpWriteHandler <category>private</category>
addContentLength: aNumber entity: anEntity | f | [ originalStream text. (Settings httpSetContentLength and: [ anEntity isMultipartByteranges not ]) ifTrue: [(f := HeaderField name: 'Content-length') value:aNumber. f writeOn: originalStream.]. originalStream cr. ] ensure: [ originalStream binary]
addTransferChunked: aStream | f | f := TransferEncoding chunkedTransfer. originalStream text. [ f writeOn: originalStream. originalStream cr. ] ensure: [ originalStream binary].
finishEmptyBodyMessage: anEntity self addContentLength: 0 entity: anEntity
setTransferContext: aMimeEntity "The Internet Assigned Numbers Authority (IANA) acts as a registry for transfer-coding value tokens. Initially, the registry contains the following tokens: 'chunked', 'identity', 'gzip', 'compress', and 'deflate' Transfer-Encoding: gzip Transfer-Encoding: chunked If the printer is set to send a message in gzip format, we will send the message as gzipped and chunked. Multipart messages and big messages are sent as chunked ones " | coll | coll := OrderedCollection new. aMimeEntity isHttpEntity ifFalse: [^coll]. self useGZipTransfer ifTrue: [coll add: TransferEncoding gzipTransfer]. ^coll
</methods> <methods> Net.HttpWriteHandler <category>printing utilities</category>
printHeader: aMessageHeader aMessageHeader removeKey: 'content-length'. super printHeader: aMessageHeader
printPreambule: aMessageBody ^true
printSimpleBodyStream: aStream entity: anEntity self writeFrom: aStream to: self stream
</methods> <methods> Net.HttpWriteHandler <category>private prepare streams</category>
prepareStream: aStream forMessageBody: aMessage | streamx | streamx := self shouldChunk ifTrue: [ (ChunkedWriteStream on: aStream) chunkSize: self chunkSize; yourself ] ifFalse: [ (aMessage body isSimple and: [aMessage body size > 0 and: [self useGZipTransfer not]]) ifTrue: [ "If we know the size of a simple body upfront we can avoid the cost of buffering the body in the BodyWriteStream" self addContentLength: aMessage body size entity: aMessage. ^aStream lineEndCRLF ] ifFalse: [ BodyWriteStream on: aStream ]]. self useGZipTransfer ifTrue: [streamx := OS.ZLib.GZipWriteStream bestCompressionOn: streamx]. streamx := EncodedStream on: streamx encodedBy: (StreamEncoder new: self defaultEncoding). streamx lineEndCRLF. ^streamx
</methods> <methods> Net.HttpWriteHandler class <category>default values</category>
shouldChunkValue ^true
useGZipTransferValue ^false
</methods> <methods> Net.HttpWriteHandler class <category>defaults</category>
defaultChunkSize ^ChunkedWriteStream defaultWriteLimit
shouldChunk ^shouldChunk ifNil: [shouldChunk := self shouldChunkValue]
shouldChunk: aBoolean shouldChunk := aBoolean
useGZipTransfer ^useGZipTransfer ifNil: [useGZipTransfer := self useGZipTransferValue]
useGZipTransfer: aBoolean useGZipTransfer := aBoolean
</methods> <methods> Net.Cookie2Field <category>printing</category>
printValueOn: aStream value notNil ifTrue: [aStream nextPutAll: '$version=', self value printString ]
</methods> <methods> Net.Cookie2Field <category>accessing</category>
version ^self value
version: aNumber self value: aNumber
</methods> <methods> Net.Cookie2Field <category>parsing</category>
doParse: scanner | vname | vname := scanner nextToken. vname asLowercase = '$version' ifFalse: [ ^self error: ((#DetectedInvalidVersionCookie2 << #net >> 'Detected invalid Cookie2 version: <1s>') expandMacrosWith: name)]. ^scanner nextToken = $= ifTrue: [ scanner nextToken asNumber ] ifFalse: [ self error: (#DetectedInvalidCookie2Header << #net >> 'Detected invalid Cookie2 header') ]
</methods> <methods> Net.Cookie2Field class <category>parsing</category>
fieldNames ^#('cookie2' )
</methods> <methods> Net.Cookie2Field class <category>instance creation</category>
version: aNumber ^self new name: self fieldNames first; version: aNumber; yourself
</methods> <methods> Net.HttpParser <category>parsing</category>
endMessageBody: aBody from: aStream "Apparently when chunking it is allowed to append additional header fields after the chunked body, referred to as a 'trailer'. Go figure, I wonder how many HTTP stacks can handle that. In any case we will handle it too." | rfc822Scanner | aBody parent isChunked ifTrue: [ aStream text. rfc822Scanner := self scannerOn: aStream. "Check if there are no an optional trailer containing entity-header for chunked messages " rfc822Scanner peekForEndOfLine ifFalse: [self privateParseHeader: aBody parent header scanner: rfc822Scanner]]. super endMessageBody: aBody from: aStream
startMessageFrom: aStream | scanner fLine rfc822Scanner aString | aStream text. rfc822Scanner := self scannerOn: aStream. aString := rfc822Scanner nextLine. aString isEmpty ifTrue: [^HttpStatusLineError new messageText: (#EmptyHttpResponseStatusLine << #net >> 'Can not read external stream, returns empty the Http response status line') asString; raiseSignal]. scanner := self scannerOn: aString readStream. fLine := ('http' match: scanner nextToken asLowercase) ifTrue: [HttpResponseStatusLine readFrom: aString readStream] ifFalse: [HttpRequestLine readFrom: aString readStream ]. (fLine isNil or: [ fLine isValid not ]) ifTrue: [ ^HttpEntityError new messageText: ((#WrongResponseStatusLine << #net >> 'Wrong response status line: <1s>') expandMacrosWith: fLine printString); raiseSignal ]. ^self handler startMessage: fLine.
</methods> <methods> Net.HttpParser class <category>defaults</category>
encoder ^HttpConnection defaultEncoding
</methods> <methods> Net.SetCookieValue <category>accessing</category>
comment ^self params at: #comment ifAbsent: [nil]
comment: aString self params at: #comment put: aString
expires ^self params at: #expires ifAbsent: [nil]
expires: aTimestamp self params at: #expires put: aTimestamp
maxAge ^self params at: #'max-age' ifAbsent: [ nil ]
maxAge: aNumber self params at: #'max-age' put: aNumber
secure ^self params at: #secure ifAbsent: [false]
secure: aBoolean aBoolean ifTrue: [self params at: #secure put: aBoolean] ifFalse: [self params removeKey: #secure ifAbsent: [nil]].
</methods> <methods> Net.SetCookieValue <category>converting</category>
acceptDomain: aString ^'*', self domain asLowercase match: aString asLowercase
acceptPath: aString ^'*', self path match: aString
acceptPort: aNumber ^true
asCookie | c | c := CookieValue name: self name value: self nameValue. self isNetscapeStyle ifTrue: [^c]. self path notNil ifTrue: [c path: self path]. self domain notNil ifTrue: [ c domain: self domain]. self port notNil ifTrue: [ c port: self port]. ^c
</methods> <methods> Net.SetCookieValue <category>testing</category>
isExpired ^(self isRFCStyle and: [self maxAge notNil and: [Timestamp now > (Timestamp fromSeconds: self maxAge)]]) or: [self isNetscapeStyle and: [self expires notNil and: [Timestamp now > self expires]]]
isNotExpired ^self isExpired not
shouldBeDiscard ^false
shouldNotBeDiscard ^self shouldBeDiscard not
</methods> <methods> Net.SetCookieValue <category>parsing-printing params</category>
commentPrintString ^(self comment asByteArrayEncoding: #utf8 ) asString
expiresPrintString "Return a properly formatted date string using GMT." | GMTSeconds | GMTSeconds := Timestamp fromSeconds: (TimeZone reference convertLocalSecondsToGMT: self expires asSeconds). ^TimestampPrintPolicy print: GMTSeconds using: 'ddd, dd mmm yyyy hh:mm:ss GMT'
maxAgePrintString ^self maxAge printString
securePrintString ^nil
setComment: aString self comment: (aString asByteArray withEncoding: #utf8 ) readStream contents
setExpires: aString self expires: (RFC822Scanner readDateAndTimeFrom: aString readStream)
setMaxAge: aString self maxAge: aString asNumber
setSecure: aBoolean self secure: aBoolean
</methods> <methods> Net.SetCookieValue <category>private-utility</category>
expireAfterDays: aNumber "Mark this cookie for expiration after aNumber of days from now." | now | now := Time dateAndTimeNow. self expires: (Timestamp fromDate: ((now at: 1) addDays: aNumber) andTime: (now at: 2))
expireAfterHours: aNumber "Mark this cookie for expiration after aNumber of hours from now." | now increment | now := Time dateAndTimeNow. increment := Time new hours: aNumber minutes: 0 seconds: 0. self expires: (Timestamp fromDate: (now at: 1) andTime: ((now at: 2) addTime: increment))
expireImmediately "Mark this cookie for immediate expiration." | now | now := Time dateAndTimeNow. self expires: (Timestamp fromDate: ((now at: 1) addDays: -1) andTime: (now at: 2))
</methods> <methods> Net.SetCookieValue <category>initialize-release</category>
initialize super initialize. setSelectors at: #secure put: #setSecure:; at: #'max-age' put: #setMaxAge:; at: #comment put: #setComment:; at: #expires put: #setExpires:. printSelectors at: #'max-age' put: #maxAgePrintString; at: #comment put: #commentPrintString; at: #expires put: #expiresPrintString; at: #secure put: #securePrintString.
</methods> <methods> Net.SetCookieValue class <category>defaults</category>
restoreValueFrom: anXMLElement ^SetCookieField readFrom: anXMLElement elements first text readStream
</methods> <methods> Net.SetCookie2Value <category>parsing-printing params</category>
commentURLPrintString ^self commentURL asString
discardPrintString ^nil
setCommentURL: aString ^self commentURL: aString asURI
setDiscard: aBoolean self discard: aBoolean
</methods> <methods> Net.SetCookie2Value <category>accessing</category>
commentURL ^self params at: #commenturl ifAbsent: [nil ]
commentURL: anURL ^self params at: #commenturl put: anURL
discard ^self params at: #discard ifAbsent: [ false ]
discard: aBoolean aBoolean ifTrue: [self params at: #discard put: aBoolean] ifFalse: [self params removeKey: #discard ifAbsent: [nil]].
</methods> <methods> Net.SetCookie2Value <category>converting</category>
acceptPort: aNumber ^self port notEmpty
</methods> <methods> Net.SetCookie2Value <category>initialize-release</category>
initialize super initialize. setSelectors at: #commenturl put: #setCommentURL:; at: #discard put: #setDiscard:. printSelectors at: #commenturl put: #commentURLPrintString; at: #discard put: #discardPrintString. self setRFCStyle.
</methods> <methods> Net.SetCookie2Value <category>testing</category>
shouldBeDiscard ^(self isRFCStyle and: [self discard ])
</methods> <methods> Net.SetCookie2Value class <category>defaults</category>
restoreValueFrom: anXMLElement ^(SetCookie2Field readFrom: ( 'Set-Cookie2: ', anXMLElement elements first text ) readStream) value first
</methods> <methods> Net.SetCookie2Value class <category>instance creation</category>
netscapeStyleName: nString value: vString ^self name: nString value: vString
</methods> <methods> Net.HttpEntity <category>testing</category>
canBeDecoded ^(self transferEncoding isNil and: [ self contentEncoding isNil ])
hasConnectionClose "Does the receiver have a Connection: close header field ? ^<Boolean> " self connection isNil ifTrue: [ ^false]. ^(self connection detect: [ :val | 'close' match: val ] ifNone: [ nil ]) notNil
hasConnectionKeepAlive "Does the receiver have a Connection: keep-alive header field ? ^<Boolean> " self connection isNil ifTrue: [ ^false]. ^(self connection detect: [ :val |'keep-alive' match: val ] ifNone: [ nil ]) notNil
hasTransferEncoding ^self transferEncoding ~~ nil
isChunked | coll | ^(coll := self transferEncoding) notNil and: [coll anySatisfy: [:vx | 'chunked' match: vx]]
isCompressed ^self isContentEncodingGZip or: [ self isTransferEncodingGZip ]
isConnectionPersistent "Does the receiver indicate a persistent connection. ^<Boolean> " ^self isConnectionTransient not
isConnectionTransient "Does the receiver indicate a transient connection. ^<Boolean> " ^self isHttp10 ifTrue: [ self hasConnectionKeepAlive not ] ifFalse: [ self hasConnectionClose ].
isExtended ^(self fields detect: [ :field | self extendedFieldNames includes: field name] ifNone: [ nil] ) notNil
isHttp10 ^self subclassResponsibility
isHttpEntity ^true
isMandatory ^self isExtended
isMimeEntity ^false
isMultipartByteranges | v | ^(v := self contentType ) ~~ nil and: ['multipart/byteranges' match: v ]
isResponse ^false
isTransferEncodingGZip | coll | ^(coll := self transferEncoding) notNil and: [coll anySatisfy: [:vx | 'gzip' match: vx]]
isValid ^self subclassResponsibility
keepAlive "Persistent connections are the default for HTTP/1.1 messages; HTTP/1.1 spec introduce a new keyword (Connection: close) for declaring non-persistence. HTTP/1.1 defines the 'close' connection option for the sender to signal that the connection will be closed after completion of the response. Persistent connections in HTTP/1.0 must be explicitly negotiated as they are not the default behavior. When it connects to an origin server, an HTTP/1.0 client MAY send the Keep-Alive connection-token : Connection: Keep-Alive An HTTP/1.0 server would then respond with the Keep-Alive connection token and the client may proceed with an HTTP/1.0 (or Keep-Alive) persistent connection. A client MUST NOT send the Keep-Alive connection token to a proxy server as HTTP/1.0 proxy servers do not obey the rules of HTTP/1.1 for parsing the Connection header field." self connection isNil ifTrue: [ ^false]. ^(self connection detect: [ :val |'keep-alive' match: val ] ifNone: [ nil ]) notNil
needsContentTransferEncoding ^false
</methods> <methods> Net.HttpEntity <category>mandatory extensions</category>
addFor: fieldName namespace: nsString "Add new mandatory field - man with specified namespace - http://www.copyright.org/rights-management namespace id is generated dynamically" "Man: http://www.copyright.org/rights-management; ns= xx" | id | id := self assignNextNamespaceId. self addFor: fieldName namespace: nsString id: id. ^id
addFor: fieldName namespace: nsString id: idString "Add new mandatory field - man with specified namespace - http://www.copyright.org/rights-management and id - 16" "Man: http://www.copyright.org/rights-management; ns=16" self addField: ( ManOptField field: fieldName namespace: nsString id: idString). ^idString
allExtendedFieldsForNamespace: nsString "Returns collection of extended fields for the specified namespace" "Man: http://www.copyright.org/rights-management; ns=16 C-Opt: http://www.copyright.org/rights-management; ns=15" | list list1 | list := OrderedCollection new: 10. (list1 := self allMandatoryFieldsForNamespace: nsString) isEmpty not ifTrue: [ list addAll: list1 ]. (list1 := self allOptionalFieldsForNamespace: nsString) isEmpty not ifTrue: [ list addAll: list1 ]. ^list
allFieldsFor: fieldName namespace: nsString "Returns collection of specified extended fields for the specified namespace" "Man: http://www.copyright.org/rights-management; ns=16 Man: http://www.copyright.org/rights-management; ns=15" ^(self fieldsAt: fieldName) select: [ :field | (field namespaceMapAt: nsString) notNil ]
allFieldsWithId: idString "Returns collection of fields with the same header prefix ( namespace id)" "16-copyright: http:/www.org/copyright.html 16-contributions: http:/www.org/patches.html" ^self fields select: [ :field | (idString, '-*') match: field name]
allIdsForNamespace: nsString "Returns collection of namespace id's for all extended fields" "Man: http://www.copyright.org/rights-management; ns=16 Opt: http://www.copyright.org/rights-management; ns=15" "#( '16' '15')" | list | list := OrderedCollection new: 10. self extendedFieldNames do: [ :fname | (self namespaceMapFor: fname) keysAndValuesDo: [ :k :v | (k equivalentTo: nsString ignoreCase: true) ifTrue: [ list add: v]]]. ^list
allMandatoryFieldsForNamespace: nsString "Returns collection of namespace id's for mandatory fields" "Man: http://www.copyright.org/rights-management; ns=16 C-Man: http://www.copyright.org/rights-management; ns=15" "#( '16' '15')" | list1 list | list := OrderedCollection new: 10. self mandatoryFieldNames do: [ :fieldName | (list1 := (self fieldsAt: fieldName) select: [ :field | (field namespaceMapAt: nsString) notNil ]) isEmpty not ifTrue: [ list addAll: list1]]. ^list
allOptionalFieldsForNamespace: nsString "Returns collection of namespace id's for optional fields" "Opt: http://www.copyright.org/rights-management; ns=16 C-Opt: http://www.copyright.org/rights-management; ns=15" "#( '16' '15')" | list1 list | list := OrderedCollection new: 10. self optionalFieldNames do: [ :fieldName | (list1 := (self fields at: fieldName) select: [ :field | (field namespaceMapAt: nsString) notNil ]) isEmpty not ifTrue: [ list addAll: list1]]. ^list
assignNextNamespaceId "Dynamically creates next namespace id and returns it as a string" self nextNamespaceId: self nextNamespaceId + 1. ^self nextNamespaceId printString
extendedFieldForId: idString "Returns an extended field with the specified namespace id" "Man: http://www.copyright.org/rights-management; ns=16" | field | (field := self mandatoryFieldForId: idString) notNil ifTrue: [ ^field ]. (field := self optionalFieldForId: idString) notNil ifTrue: [ ^field ]. ^nil
extendedFieldNames ^#('man' 'c-man' 'opt' 'c-opt')
fieldAt: fieldName id: idString "Returns field with the specified namespace id (prefix) if this field is absent creates new header field " "16-copyright: http:/www.org/copyright.html" ^self getFieldAt: ( idString, '-', fieldName)
fieldAt: fieldName put: aValue id: idString "Set value (http:/www.org/copyright.html) for the specified field name (copyright) with namespace id (16)" "16-copyright: http:/www.org/copyright.html" (self getFieldAt: ( idString, '-', fieldName)) value: aValue
fieldValueAt: fieldName id: idString "Returns value (http:/www.org/copyright.html) for the specified field (16-copyright)" "16-copyright: http:/www.org/copyright.html" ^self getValueFor: ( idString, '-', fieldName)
idFor: fieldName namespace: nsString "Returns namespace id for the specified mandatory(optional) field name and namespace" "Man: http://www.copyright.org/rights-management; ns=16" " self idFor: 'man' namespace: 'http://www.copyright.org/rights-management' returns 16 " ^(self namespaceMapFor: fieldName) at: nsString
mandatoryFieldForId: idString "Returns mandatory field for the specified id" "Man: http://www.copyright.org/rights-management; ns=16" "C-Man: http://www.copyright.org/rt; ns=15" | field | self mandatoryFieldNames do: [ :fieldName | (field := (self fieldsAt: fieldName) detect: [ :fd | (fd namespaceMapKeyAtValue: idString) notNil ] ifNone: [nil]) notNil ifTrue: [ ^field ]]. ^nil
mandatoryFieldNames ^#('man' 'c-man')
namespaceFor: fieldName id: idString "Returns namespace for the specified mandatory field and id" "Man: http://www.copyright.org/rights-management; ns=16" " self namespaceFor: 'man' id: '16' returns 'http://www.copyright.org/rights-management' " (self namespaceMapFor: fieldName) keysAndValuesDo: [:aKey :aValue | aValue = idString ifTrue: [^aKey]]. ^nil
namespaceForId: idString "Returns namespace for the specified id" "Man: http://www.copyright.org/rights-management; ns=16" " self namespaceForId: '16' returns: 'http://www.copyright.org/rights-management' " self namespaceMap keysAndValuesDo: [:aKey :aValue | aValue = idString ifTrue: [^aKey]]. ^nil
namespaceMap "Returns a dictionary all namespaces and id's namespace is a key namespace id is a value" | dict | dict := Dictionary new. self extendedFieldNames do: [ :fname | (self namespaceMapFor: fname) associations do: [ :ea | dict add: ea] ]. ^dict
namespaceMapFor: fnString "Returns a dictionary namespaces and id's for the specified field name ('man' 'opt' ...) namespace is a key namespace id is a value" | dict | dict := Dictionary new. (self fieldsAt: fnString) do: [ :field | field namespaceMap associations do: [ :ea | dict add: ea] ]. ^dict
nextNamespaceId "Returns namespace id (header-prefix)" ^nextNamespaceId isNil ifTrue: [ nextNamespaceId := 10] ifFalse: [ nextNamespaceId ]
nextNamespaceId: aNumber "Sets namespace id (header-prefix)" nextNamespaceId := aNumber
optionalFieldForId: idString "Returns optional field for the specified id" "Opt: http://www.copyright.org/rights-management; ns=16" "C-Opt: http://www.copyright.org/rt; ns=15" | field | self optionalFieldNames do: [ :fieldName | (field := (self fieldsAt: fieldName) detect: [ :fd | (fd namespaceMapKeyAtValue: idString) notNil ] ifNone: [nil]) notNil ifTrue: [ ^field ]]. ^nil
optionalFieldNames ^#('opt' 'c-opt')
removeNamespace: nsString "Removes all fields for the specified namespace" (self allIdsForNamespace: nsString) do: [ :id | self removeNamespaceId: id ].
removeNamespaceId: idString "Removes all fields for the specified namespace id" "Man: 'http://www.copyright.org/rights-management'; ns=14 Man: 'http://www.copyright.org/rights-mgt'; ns=15, 'http://www.copyright.org/rt13'; ns=13 14-Credentials: 'g5gj262jdw@4df' 13-Credentials: 'QQQQ' self removeNamespaceId: '13'. Result: Man: http://www.copyright.org/rights-management; ns=14 Man: 'http://www.copyright.org/rights-mgt'; ns=15 14-Credentials: 'g5gj262jdw@4df' " | field | (self allFieldsWithId: idString) do: [ :fd | self removeFieldAt: fd name]. field := self extendedFieldForId: idString. field removeId: idString. field value isEmpty ifTrue: [ self removeField: field ].
</methods> <methods> Net.HttpEntity <category>accessing fields</category>
allow ^self fieldValueAt: 'allow'
allow: stringOrCollection (self getFieldAt: 'allow') value: stringOrCollection
cacheControl ^self fieldAt: 'cache-control'
cacheControl: aStringOrAssociationOrCacheControl (aStringOrAssociationOrCacheControl isKindOf: CacheControl) ifTrue: [self removeFieldAt: 'cache-control'. self addField: aStringOrAssociationOrCacheControl] ifFalse: [(self getFieldAt: 'cache-control') addDirective: aStringOrAssociationOrCacheControl]
connection ^self fieldValueAt: 'connection'
connection: aString (self getFieldAt: 'connection') value: aString
contentBase ^self fieldValueAt: 'content-base'
contentBase: aString (self getFieldAt: 'content-base') value: aString
contentEncoding ^self fieldValueAt: 'content-encoding'
contentEncoding: aCollectionField (self getFieldAt: 'content-encoding') value: aCollectionField
contentLanguage ^self fieldValueAt: 'content-language'
contentLanguage: aString (self getFieldAt: 'content-language') value: aString
contentLocation ^self fieldValueAt: 'content-location'
contentLocation: aString (self getFieldAt: 'content-location') value: aString
contentMD5 ^self fieldValueAt: 'content-md5'
contentMD5: aString (self getFieldAt: 'content-md5') value: aString
contentRange ^self fieldValueAt: 'content-range'
contentRange: aString (self getFieldAt: 'content-range') value: aString
cookie ^self fieldAt: 'cookie'
cookie2 ^self fieldAt: 'cookie2'
cookie2: aCookie2Field (self getFieldAt: 'cookie2') value: aCookie2Field
cookie: aCookieField self fieldAt: 'cookie' put: aCookieField
date ^self fieldValueAt: 'date'
date: aTimestampOrStringOrArray (self getFieldAt: 'date') value: aTimestampOrStringOrArray
etag ^self fieldValueAt: 'etag'
etag: aString (self getFieldAt: 'etag') value: aString
expires ^self fieldValueAt: 'expires'
expires: aTimestampOrStringOrArray (self getFieldAt: 'expires') value: aTimestampOrStringOrArray
from ^self fieldValueAt: 'from'
from: aString (self getFieldAt: 'from') value: aString
lastModified ^self fieldValueAt: 'last-modified'
lastModified: aTimestampOrStringOrArray (self getFieldAt: 'last-modified') value: aTimestampOrStringOrArray
pragma ^self fieldValueAt: 'pragma'
pragma: aString (self getFieldAt: 'pragma') value: aString
removeFromCacheControl: aString (self getFieldAt: 'cache-control') removeDirective: aString
setCookie ^self fieldAt: 'set-cookie'
setCookie2 ^self fieldAt: 'set-cookie2'
setCookie2: aSetCookie2Field (self getFieldAt: 'set-cookie2') value: aSetCookie2Field
setCookie: aSetCookieField (self getFieldAt: 'set-cookie') value: aSetCookieField
setCookieFields | coll sc | coll := OrderedCollection new. (sc := self fieldAt: 'set-cookie') notNil ifTrue: [ coll add: sc ]. (sc := self fieldAt: 'set-cookie2') notNil ifTrue: [ coll add: sc ]. ^coll
transferCoding ^self fieldValueAt: 'transfer-coding'
transferCoding: aString ^self fieldValueAt: 'transfer-coding' put: aString
transferEncoding ^self fieldValueAt: 'transfer-encoding'
transferEncoding: aStringOrColl | val | val := aStringOrColl isString ifTrue: [ OrderedCollection with: aStringOrColl] ifFalse: [ aStringOrColl ]. ^self fieldValueAt: 'transfer-encoding' put: val
via ^self fieldValueAt: 'via'
via: aString (self getFieldAt: 'via') value: aString
</methods> <methods> Net.HttpEntity <category>accessing</category>
keepAlive: aBoolean | val token | token := aBoolean ifTrue: ['Keep-Alive'] ifFalse: ['close']. val := (self getFieldAt: 'connection') value. #('Keep-Alive' 'close') do: [ :t | val removeAllSuchThat:[ :elem | t match: elem ]]. val add: token.
messageLine ^self subclassResponsibility
messageLine: anObject self subclassResponsibility
</methods> <methods> Net.HttpEntity <category>accessing body parts</category>
byteContents | s | ^(s := self byteSource) isNil ifTrue: [ nil ] ifFalse: [ s reset; contents ]
byteSource ^self body byteSource
byteSource: aByteArrayStream self body byteSource: aByteArrayStream
contents "Returns the message body contents. If the entity still has compressed body contents the method returns the compressed bytes " | v ce | ^((ce := self contentEncoding) notNil and: ['gzip' match: ce ]) ifTrue: [self byteContents] ifFalse: [(v := self body value) ifNotNil: [ v asString ]]
decodedContents "Returns decoded body contents. If the entity still has compressed body contents the method decompresses the body and returns decoded body contents " | ce | ^((ce := self contentEncoding) notNil and: ['gzip' match: ce ]) ifTrue: [(self body decompressedContents withEncoding: self charset ) readStream contents] ifFalse: [self decodedContentsWith: self charset ]
decompressedContents "Returns decompressed body contents. The body contents won't be changed " | ce | ce := self contentEncoding. ^(ce notNil and: ['gzip' match: ce ]) ifTrue: [self body decompressedContents] ifFalse: [self decodedContents]
</methods> <methods> Net.HttpEntity <category>private</category>
decodedByteContentsStream | ce | ^((ce := self contentEncoding) notNil and: ['gzip' match: ce ]) ifTrue: [(self body decompressedContents withEncoding: self charset ) readStream ] ifFalse: [super decodedByteContentsStream]
hasByteSource ^self byteSource notNil
</methods> <methods> Net.HttpEntity <category>printing options</category>
chunkSize ^chunkSize
chunkSize: aNumber chunkSize := aNumber
doChunk self shouldChunk: true
doNotChunk self shouldChunk: false
shouldChunk ^shouldChunk
shouldChunk: aBoolean shouldChunk := aBoolean
useGZipTransfer ^useGZipTransfer
useGZipTransfer: aBoolean useGZipTransfer := aBoolean
</methods> <methods> Net.HttpEntity <category>parsing options</category>
decodeContents ^decodeContents
decodeContents: aBoolean decodeContents := aBoolean
decompressContents ^decompressContents
decompressContents: aBoolean decompressContents := aBoolean
newBuilder ^super newBuilder decodeContents: self decodeContents; decompressContents: self decompressContents; yourself
</methods> <methods> Net.HttpEntity <category>visiting</category>
acceptVisit: aVisitor with: argument ^aVisitor acceptMessage: self with: argument
</methods> <methods> Net.HttpEntity <category>writing</category>
newWriter ^super newWriter useGZipTransfer: useGZipTransfer; chunkSize: chunkSize; shouldChunk: shouldChunk; yourself
</methods> <methods> Net.HttpEntity class <category>defaults</category>
defaultBuilderType ^HttpBuildHandler
defaultPrinterType ^HttpPrintHandler
defaultWriterType ^HttpWriteHandler
</methods> <methods> Net.HttpRequest <category>accessing</category>
headerOnly ^self requestLine headerOnly
hostName ^self hostPortToConnect first
messageLine ^self requestLine
messageLine: aRequestLine self requestLine: aRequestLine
method ^self requestLine method
port ^self hostPortToConnect last
protocol ^self requestLine protocol
requestLine ^requestLine
requestLine: aRequestLine requestLine := aRequestLine.
url | path | ^self requestLine hasAbsoluteURI ifTrue: [self requestLine url ] ifFalse: [ path := self requestLine path. path first =$/ ifTrue: [path := path copyFrom: 2 to: path size]. HttpURL host: self host pathString: path ]
url: aURI ^self requestLine url: aURI
useProxy ^self requestLine useProxy
useProxy: aBoolean self requestLine useProxy: aBoolean
version ^self requestLine version
version: aString ^self requestLine version: aString
</methods> <methods> Net.HttpRequest <category>private</category>
hostPortToConnect "1.If Request-URI is an absoluteURI, the host is part of the Request-URI. Any Host header field value in the request MUST be ignored. 2. If the Request-URI is not an absoluteURI, and the request includes a Host header field, the host is determined by the Host header field value. 3. If the host as determined by rule 1 or 2 is not a valid host on the server, the response MUST be a 400 (Bad Request) error message. " | host str port | self requestLine hasAbsoluteURI ifTrue: [ ^Array with: self requestLine host with: self requestLine port] ifFalse: [ (host := self host) ~~ nil ifTrue: [ str := host readStream. host := str upTo: $:. (port := Number readFrom: str) = 0 ifTrue: [ port := nil]. ^Array with: host with: port]]. HttpBadRequest new messageText: (#HostIsNotSpecified << #net >> 'Host is not specified'); raiseSignal
method: aMethodString url: requestURI requestLine := HttpRequestLine new method: aMethodString; url: requestURI asURI; yourself
</methods> <methods> Net.HttpRequest <category>mandatory extensions</category>
extendedMethod ^self requestLine extendedMethod
</methods> <methods> Net.HttpRequest <category>accessing fields</category>
accept " Returns all AcceptFields " ^self fieldsAt: 'accept'
accept: aStringOrAcceptField "Sets a value the parameter can be a string or instance of AcceptField" aStringOrAcceptField isString ifTrue: [ (self getFieldAt: 'accept') addMedia: aStringOrAcceptField] ifFalse: [ self removeFieldAt: 'accept'. self addField: aStringOrAcceptField]
acceptCharset "Returns collection of AcceptCharsetFields" ^self fieldsAt: 'accept-charset'
acceptCharset: aStringOrAcceptCharsetField "Sets a value the parameter can be a string or instance of AcceptCharsetField" aStringOrAcceptCharsetField isString ifTrue: [ (self getFieldAt: 'accept-charset') addCharset: aStringOrAcceptCharsetField] ifFalse: [ self removeFieldAt: 'accept-charset'. self addField: aStringOrAcceptCharsetField]
acceptEncoding ^self fieldValueAt: 'accept-encoding'
acceptEncoding: aStringOrCollection (self getFieldAt: 'accept-encoding') value: aStringOrCollection
acceptLanguage " Returns all AcceptLanguageFields " ^self fieldsAt: 'accept-language'
acceptLanguage: aStringOrAcceptLanguageField "Sets a value the parameter can be a string or instance of AcceptLanguage" aStringOrAcceptLanguageField isString ifTrue: [ (self getFieldAt: 'accept-language') addLanguage: aStringOrAcceptLanguageField] ifFalse: [ self removeFieldAt: 'accept-language'. self addField: aStringOrAcceptLanguageField]
authorization ^self fieldAt: 'authorization'
authorization: aStringOrAuthorizationField "Sets a value the parameter can be a string or instance of AuthenticateChallengeField" aStringOrAuthorizationField isString ifTrue: [ (self getFieldAt: 'authorization') addScheme: aStringOrAuthorizationField] ifFalse: [ self removeFieldAt: 'authorization'. self addField: aStringOrAuthorizationField]
host ^self fieldValueAt: 'host'
host: aString (self getFieldAt: 'host') value: aString
ifMatch ^self fieldValueAt: 'if-match'
ifMatch: aStringOrCollection (self getFieldAt: 'if-match') value: aStringOrCollection
ifModifiedSince ^self fieldValueAt: 'if-modified-since'
ifModifiedSince: aString (self getFieldAt: 'if-modified-since') value: aString
ifNoneMatch ^self fieldValueAt: 'if-none-match'
ifNoneMatch: aStringOrCollection (self getFieldAt: 'if-none-match') value: aStringOrCollection
ifRange ^self fieldValueAt: 'if-range'
ifRange: aString (self getFieldAt:'if-range') value: aString
ifUnModifiedSince ^self fieldValueAt: 'if-unmodified-since'
ifUnModifiedSince: aString (self getFieldAt: 'if-unmodified-since') value: aString
maxForwards ^self fieldValueAt: 'max-forwards'
maxForwards: aString (self getFieldAt: 'max-forwards') value: aString
proxyAuthorization ^self fieldValueAt: 'proxy-authorization'
proxyAuthorization: aString (self getFieldAt: 'proxy-authorization' ) value: aString
referer ^self fieldValueAt: (#referer << #net >> 'referer')
referer: aString (self getFieldAt: 'referer') value: aString
userAgent ^self fieldValueAt: 'user-agent'
userAgent: aString (self getFieldAt: 'user-agent') value: aString
</methods> <methods> Net.HttpRequest <category>testing</category>
hasHostField ^self host notNil
isHttp10 ^self requestLine isHttp10
isValid ^(self requestLine isValid and: [ self host notNil])
</methods> <methods> Net.HttpRequest <category>transfer encodings</category>
transferFieldOrder " HTTP request recommends field order (if present) to be as follows. Order for remaining fiedls does not matter " ^#('host')
</methods> <methods> Net.HttpRequest <category>low-level command interface</category>
execute " Create http client, connect, send request and answer HttpResponse " | client | client := self newClient. ^[client executeRequest: self] ensure: [ client ifNotNil: [ client close]]
executeDo: aBlock " Create http client, connect, send request and pass http connection stream to the specified block " ^self newClient executeRequest: self do: aBlock.
newClient ^HttpClient new
</methods> <methods> Net.HttpRequest <category>obsolete</category>
addAuthorizationCode: code "obsolete" self authorization: code
addProxyAuthorizationCode: code "obsolete" self proxyAuthorization: code
proxyRealm: rString username: unString password: pString "obsolete" | code | ^(code := BasicAuthentication encodeUser: unString password: pString) notNil ifTrue:[ self addProxyAuthorizationCode: rString, ' ', code ] ifFalse: [ nil]
realm: rString username: unString password: pString "obsolete" | code | ^(code := BasicAuthentication encodeUser: unString password: pString) notNil ifTrue:[ self addAuthorizationCode: rString, ' ', code ] ifFalse: [ nil]
</methods> <methods> Net.HttpRequest <category>parsing options</category>
newBuilder ^super newBuilder headerOnly: self headerOnly; yourself
</methods> <methods> Net.HttpRequest class <category>Http commands</category>
delete: urlString ^self method: 'DELETE' url: urlString
get: urlString ^self method: 'GET' url: urlString
headers: urlString ^self method: 'HEAD' url: urlString
post: urlString ^self method: 'POST' url: urlString
put: urlString ^self method: 'PUT' url: urlString
</methods> <methods> Net.HttpRequest class <category>defaults</category>
defaultContentType ^MimeTypeDescriptor contentTypeHtml
</methods> <methods> Net.HttpRequest class <category>instance creation</category>
method: aMethodString url: requestURI ^self new method: aMethodString url: requestURI; yourself
</methods> <methods> Net.HttpAuthentication <category>accessing</category>
authChallenge ^authChallenge
authChallenge: anAuthenticateChallenge authChallenge := anAuthenticateChallenge.
authPolicy ^authPolicy
authValue ^authValue
authValue: anAuthenticationValue authValue := anAuthenticationValue
password ^self user password
pathString ^pathString
realm ^self user realm
scheme ^self class scheme
user ^user
username ^self user username
</methods> <methods> Net.HttpAuthentication <category>authorization</category>
acceptAuthInfoFrom: anAuthInfo
addAuthorizationTo: aHttpRequest for: headerString | header | self setPathStringFrom: aHttpRequest. header := aHttpRequest getFieldAt: headerString. self verifyUser. (self isAuthorized or: [self isAuthorizationInProgress]) ifTrue: [ self setNextAuthorizationValueFor: header ] ifFalse: [self authValue: (header addScheme: self scheme). self setNewAuthorizationValue.]
setNewAuthorizationValue self subclassResponsibility
setNextAuthorizationValueFor: header header value add: self authValue.
setPathStringFrom: aHttpRequest pathString := aHttpRequest requestLine pathString
verifyUser (self username = self authPolicy username and: [self password = self authPolicy password]) ifFalse: [ self setUser: self authPolicy user]
</methods> <methods> Net.HttpAuthentication <category>state</category>
setAuthorizationInProgressState state := #authorizationInProgress
setAuthorizedState state := #authorized
setNotAuthorizedState authValue := nil. state := #notAuthorized
</methods> <methods> Net.HttpAuthentication <category>testing</category>
canAccept: anAuthorizationField ^false
canProceedWith: anAuthorizationField ^anAuthorizationField isNil or: [ self username ~= self authPolicy username and: [self password ~= self authPolicy password]]
isAuthorizationInProgress ^state = #authorizationInProgress
isAuthorized ^state = #authorized
isNotAuthorized ^state = #isNotAuthorized
</methods> <methods> Net.HttpAuthentication <category>initialize-release</category>
initialize self setNotAuthorizedState
setAuthPolicy: anAuthPolicyHolder authPolicy := anAuthPolicyHolder. self setUser: authPolicy user.
setUser: anHttpUser user := anHttpUser copy. self setNotAuthorizedState
</methods> <methods> Net.HttpAuthentication <category>select challenge</category>
proceedWith: authenticate | challenges | challenges := authenticate value select: [ :val | self class acceptScheme: val scheme]. self setAuthChallengeFrom: challenges. ^challenges notEmpty
selectAuthChallenge: aCollOfAuthenticateChallenge ^self realm isNil ifTrue: [ aCollOfAuthenticateChallenge first ] ifFalse: [ aCollOfAuthenticateChallenge detect: [ :chall | self user acceptsRealm: chall realm ] ifNone: [ HttpAuthenticationExc raiseRequestWith: aCollOfAuthenticateChallenge errorString: (#CannotFindRealm << #net >> 'Can not find realm <1s> in <2s>' expandMacrosWith: self realm with: aCollOfAuthenticateChallenge printString) ]]
setAuthChallenge: anAuthenticateChallenge self authChallenge: anAuthenticateChallenge. self setNotAuthorizedState.
setAuthChallengeFrom: anAuthenticateChallengeOrCollection | ch | anAuthenticateChallengeOrCollection isEmpty ifTrue: [ ^nil]. (ch := self selectAuthChallenge: anAuthenticateChallengeOrCollection) isNil ifTrue: [ HttpAuthenticationExc raiseRequestWith: anAuthenticateChallengeOrCollection errorString: (#CanNotProcessAuthChallenge << #net >> 'Can not process authentication challege: <1s>' expandMacrosWith: anAuthenticateChallengeOrCollection printString) ]. self setAuthChallenge: ch.
</methods> <methods> Net.HttpAuthentication class <category>accessing</category>
acceptScheme: aString ^aString match: self scheme
scheme ^self subclassResponsibility
</methods> <methods> Net.HttpAuthentication class <category>instance creation</category>
new ^super new initialize
policy: anAuthPolicy ^self new setAuthPolicy: anAuthPolicy; yourself
</methods> <methods> Net.NTLMAuthentication <category>select challenge</category>
selectAuthChallenge: aCollOfAuthenticateChallenge ^aCollOfAuthenticateChallenge first
setAuthChallenge: anAuthenticateChallenge self authChallenge: anAuthenticateChallenge. authChallenge ntlmValue ifNotNil: [decodedData := self decodeValueFrom: self authChallenge ntlmValue asByteArray readStream. self setType2Flags].
</methods> <methods> Net.NTLMAuthentication <category>accessing</category>
challenge ^self isType2 ifTrue: [ decodedData copyFrom: 25 to: 32 ] ifFalse: [ nil]
domain domain ifNil: [ (domain := Settings httpDomain) ifNil: [self error: (#HttpDomainIsNotSpecified << #net >> 'Net.Settings class>>httpDomain is not specified. Can not create NTLM Authentication message') asString ]]. ^domain
workstation ^workstation ifNil: [ workstation := SocketAccessor getHostname ]
workstation: aString workstation := aString
</methods> <methods> Net.NTLMAuthentication <category>authorization</category>
acceptAuthInfoFrom: aHttpResponse "Reset to unauthorized state. The server doesn't accept old authorization anyway " self isAuthorized ifTrue: [ self setNotAuthorizedState ]
setNewAuthorizationValue self authValue ntlmValue: self type1Value. self setAuthorizationInProgressState
setNextAuthorizationValueFor: header self authValue ntlmValue: self type3Value. header value add: self authValue. self setAuthorizedState.
setPathStringFrom: aHttpRequest aHttpRequest requestLine pathString ~= self pathString ifTrue: [pathString := aHttpRequest requestLine pathString. self setNotAuthorizedState ].
type1Value | str stream output | output := (ByteArray new: 64) writeStream. stream := EncodedStream on: output encodedBy: Base64StreamEncoder asEncoder. stream nextPutAll: 'NTLMSSP'. stream nextPutAll: (#[ 0 ] asStringEncoding: #'iso-8859-1'). "8 NTLM Message Type " stream nextPutAll: (#[ 1 0 0 0 ] asStringEncoding: #'iso-8859-1'). "12 Flags " stream nextPutAll: (#[7 32 0 0] asStringEncoding: #'iso-8859-1'). " (16) Supplied Domain (Optional) security buffer " stream nextPutAll: (#[ 0 0 0 0 0 0 0 0 ] asStringEncoding: #'iso-8859-1'). "(24) Supplied Workstation (Optional) security buffer " stream nextPutAll: (#[ 0 0 0 0 0 0 0 0 ] asStringEncoding: #'iso-8859-1'). stream close. str := (stream encodedContents withEncoding: #'iso-8859-1') readStream contents. ^str.
type3Value | str stream output offset struct| output := (ByteArray new: 64) writeStream. stream := EncodedStream on: output encodedBy: Base64StreamEncoder asEncoder. offset := 52. struct := Struct new. struct domain: (self getStringFrom: self domain asUppercase)->offset. offset := offset + struct domain key size. struct username: (self getStringFrom: self username asUppercase)->offset. offset := offset + struct username key size. struct workstation: (self getStringFrom: self workstation asUppercase)->offset. offset := offset + struct workstation key size. struct lmBuffer: ((self lmResponseFrom: self password) asStringEncoding: #'iso-8859-1')->offset. offset := offset + struct lmBuffer key size. stream nextPutAll: 'NTLMSSP'. stream nextPutAll: (#[ 0 ] asStringEncoding: #'iso-8859-1'). "8 NTLM Message Type " stream nextPutAll: (#[ 3 0 0 0 ] asStringEncoding: #'iso-8859-1'). "12 LM/LMv2 Response security buffer " self putOn: stream data: struct lmBuffer. "20 NTLM/NTLMv2 Response security buffer. Not supported " stream nextPutAll: (#[ 0 0 0 0 0 0 0 0 ] asStringEncoding: #'iso-8859-1'). "28 Domain Name security buffer " self putOn: stream data: struct domain. "36 User Name security buffer " self putOn: stream data: struct username. "44 Workstation Name security buffer " self putOn: stream data: struct workstation. "(52) start of data block " struct associations do: [ :assoc | stream nextPutAll: assoc value key ]. stream close. str := (stream encodedContents withEncoding: #'iso-8859-1') readStream contents. ^str.
</methods> <methods> Net.NTLMAuthentication <category>testing</category>
canProceedWith: anAuthorizationField (anAuthorizationField value select: [ :val | self class acceptScheme: val scheme]) notEmpty and: [(super canProceedWith: anAuthorizationField) or: [self isType2 not]]
isType2 ^decodedData notNil and: [(decodedData at: 9) = 2]
useUnicode "Negotiate Unicode (0x00000001) The server sets this flag to indicate that it will be using Unicode strings " ^flags notNil and: [ flags anyMask: 16r1 ]
</methods> <methods> Net.NTLMAuthentication <category>private</category>
decodeValueFrom: aStream | stream output char | stream := EncodedStream on: aStream encodedBy: Base64StreamEncoder asEncoder. output := (ByteArray new: 64) writeStream. [ (char := stream next) notNil ] whileTrue: [ output nextPut: char ]. ^output contents.
expand: keyBytes "Expand 7 bytes of DES key into 8 bytes with parity, i.e. add parity bit to each 7 bit block of the key. Note: our DES doesn't care about the parity bit so it's left to be whatever it is, other DES implementations may not tolerate that. " | remainder key | key := (ByteArray new: 8) writeStream. remainder := (ByteArray new: 9) writeStream. "add 0 byte to shift into, add 0x1 byte at the MSB end to make sure we're working with a valid 8 byte large int" remainder nextPut: 0; nextPutAll: keyBytes reverse; nextPut: 1. remainder := remainder contents changeClassTo: LargePositiveInteger. 8 to: 1 by: -1 do: [ :i | key nextPut: (remainder basicAt: i). remainder := remainder bitShift: -1 ]. ^key contents
getStringFrom: aString | output input ucode | ^self useUnicode ifTrue: [output := (ByteArray new: 64) writeStream. input := aString readStream. [ input atEnd ] whileFalse: [ ucode := input next asInteger. output nextPut: (ucode bitAnd: 16rFF); nextPut: (ucode bitShift: -8) ]. output contents asStringEncoding: #'iso-8859-1'.] ifFalse: [ aString ]
hash: in message: msg count: count "Produce the LM hash of 'msg' using 'count' keys from 'in' " | out des | out := (ByteArray new: 24) readWriteStream. des := Security.DES new. count timesRepeat: [ des setKey: (self expand: (in next: 7)). out nextPutAll: (des encrypt: msg) ]. ^out
lmResponseFrom: password | keys | keys := ((ByteArray new: 14) withEncoding: #ASCII) readWriteStream. keys nextPutAll: password asUppercase; binary. (14 - keys position) timesRepeat: [ keys nextPut: 0 ]. keys reset. keys := self hash: keys message: 'KGS!@#$%' asByteArray count: 2. keys nextPutAll: #[0 0 0 0 0]; reset. keys := self hash: keys message: self challenge count: 3. ^keys contents
putOn: aStream data: anAssoc | arr aString offset | aString := anAssoc key. offset := anAssoc value. arr := ByteArray new: 8. arr at: 1 put: aString size; at: 2 put: 0; at: 3 put: aString size; at: 4 put: 0; at: 5 put: offset; at: 6 put: 0; at: 7 put: 0; at: 8 put: 0. aStream nextPutAll: (arr asStringEncoding: #'iso-8859-1').
setType2Flags | arr | (self isType2 and: [(arr := decodedData copyFrom: 21 to: 24) notNil ]) ifTrue: [flags := arr changeClassTo: LargePositiveInteger ]
type1Flags | n a | n := 0. n := n maskSet: 1. " Negotiate Unicode (0x00000001) " n := n maskSet: 2. "Negotiate OEM (0x00000002) " n := n maskSet: 4. "Request Target (0x00000004)" n := n maskSet: 512. "Negotiate NTLM (0x00000200) " n := n maskSet: 4096. "Negotiate Domain Supplied (0x00001000) " n := n maskSet: 8192. "Negotiate Workstation Supplied (0x00002000)" a := ByteArray new: 5. a at: 1 put: 0. 1 to: 4 do: [ :ind | a at: (ind + 1) put: (n digitAt: ind)]. ^a copyFrom: 1 to: a size - 1
</methods> <methods> Net.NTLMAuthentication class <category>defaults</category>
scheme ^'NTLM'
</methods> <methods> Net.AcceptHeaderFields <category>accessing</category>
qValueAt: index ^(self value at: index) paramAt: 'q'
</methods> <methods> Net.AcceptHeaderFields <category>adding range</category>
addValue: vString qValue: qString | valWithParams | valWithParams := ValueWithParams newWithSeparators: self separators. valWithParams value: vString. qString notNil ifTrue: [ valWithParams paramAt: 'q' put: qString]. self value add: valWithParams. ^valWithParams
</methods> <methods> Net.AcceptHeaderFields class <category>defaults</category>
defaultSeparators ^#($; $; $, )
</methods> <methods> Net.AcceptCharsetField <category>adding charset</category>
addCharset: cString self addCharset: cString qValue: nil
addCharset: cString qValue: qString self addValue: cString qValue: qString.
</methods> <methods> Net.AcceptCharsetField <category>accessing</category>
charsetAt: index ^self value at: index
charsetTypeAt: index ^(self charsetAt: index) value
</methods> <methods> Net.AcceptCharsetField class <category>parsing</category>
fieldNames ^#('accept-charset')
</methods> <methods> Net.AcceptCharsetField class <category>instant creation</category>
charset: cString ^self charset: cString qValue: nil
charset: cString qValue: qString ^(self name: 'accept-charset') addCharset: cString qValue: qString; yourself
</methods> <methods> Net.AuthenticateField <category>adding </category>
addBasic ^self addScheme: 'Basic'
addBasicRealm: rString ^self addBasic realm: rString
addDigest ^self addScheme: 'Digest'
addDigestRealm: aString ^self addDigest realm: aString
addNegotiate ^self addScheme: 'Negotiate'
addNTLM ^self addScheme: 'NTLM'
addScheme: aString | valWithParams newVal | valWithParams := self valueWithParamsClass newWithSeparators: self separators. valWithParams value: aString. self value add: (newVal := self privateNewValueFrom: valWithParams). ^newVal
addScheme: vString realm: rString | valWithParams | valWithParams := self addScheme: vString. rString ifNotNil: [ valWithParams realm: rString]. ^valWithParams
</methods> <methods> Net.AuthenticateField <category>accessing</category>
basicScheme ^self value select: [ :each | each isBasic ]
detectRealm | coll val | coll := self basicScheme. coll addAll: self digestScheme. val := coll detect: [ :each | each realm notNil ] ifNone: [ nil ]. ^val realm
digestScheme ^self value select: [ :each | each isDigest ]
ntlmScheme ^self value select: [ :each | each isNTLM ]
scheme ^self schemes first
schemes | coll | coll := OrderedCollection new. self value do: [ :each | ('negotiate' match: each scheme asLowercase) ifFalse: [coll add: each scheme] ]. ^coll
valueWithParamsClass ^AuthenticationValue
</methods> <methods> Net.AuthenticateField <category>obsolete</category>
addBasic: vString ^self addScheme: vString
addBasic: vString realm: rString ^self addScheme: vString realm: rString
realm ^self detectRealm
</methods> <methods> Net.AuthenticateField <category>testing</category>
canNegotiate ^'negotiate' match: self first scheme asLowercase
hasBasicAuth ^self basicScheme notEmpty
hasDigestAuth ^self digestScheme notEmpty
hasNTLMAuth ^self ntlmScheme notNil
</methods> <methods> Net.AuthenticateField <category>parsing</category>
newValueFrom: scanner | authVal | authVal := self valueWithParamsClass newWithSeparators: self separators. authVal parseValue: scanner. ^self privateNewValueFrom: authVal
</methods> <methods> Net.AuthenticateField <category>private parsing</category>
privateNewValueFrom: authValue authValue isDigest ifTrue: [ ^DigestAuthenticationValue new separators: authValue separators; yourself ]. ^authValue
</methods> <methods> Net.AuthenticateField class <category>defaults</category>
defaultSeparators ^#($ $, $ )
</methods> <methods> Net.AuthenticateField class <category>parsing</category>
fieldNames ^#('www-authenticate' 'proxy-authenticate')
</methods> <methods> Net.HttpUser <category>testing</category>
acceptsRealm: aString ^self realms isEmpty or: [self realms anySatisfy: [ :each | each = aString ]]
isHttpUser ^false
</methods> <methods> Net.HttpUser <category>accessing</category>
realm ^self realms notEmpty ifTrue: [ self realms first ] ifFalse: [ nil ]
realms ^realms ifNil: [ realms := OrderedCollection new].
realms: aCollection realms := aCollection
</methods> <methods> Net.HttpUser <category>adding</category>
addRealm: aString aString ifNotNil: [ self realms add: aString]
</methods> <methods> Net.HttpException <category>printing</category>
defaultMessageText ^super defaultMessageText, '\(' withCRs, parameter printStatusLineMessage, ')'
</methods> <methods> Net.HttpException class <category>handling http responses</category>
handleResponse: resp "trigger exceptions for all responses but 2xx (success) " | exp | resp isSuccess ifFalse: [ exp := (self preferences detect: [ :ea | ea key match: resp code ]) value. exp signalWith: resp]. ^resp
initializePreferences "self initializePreferences " Preferences := (OrderedCollection new: 13) add: '400' -> HttpBadRequest; add: '401' -> HttpUnauthorizedError; add: '404' -> HttpObjectNotFound; add: '407' -> HttpProxyAuthenticationError; add: '301' -> HttpMovedError; add: '302' -> HttpMovedError; add: '510' -> HttpNotExtendedError; add: '1*' -> HttpInformationalError; add: '3*' -> HttpRedirectionError; add: '4*' -> HttpClientError; add: '5*' -> HttpServerError; add: '*' -> HttpException; yourself.
preferences Preferences isNil ifTrue: [ self initializePreferences]. ^Preferences
</methods> <methods> Net.HttpException class <category>testing</category>
mayResume ^true
</methods> <methods> Net.HttpResponseStatusLine <category>testing</category>
headerOnly ^(self code notNil and: [self code isEmpty not and: [self isInformationalReply or: [#('204' '304') includes: self code]]]) ifTrue: [true] ifFalse: [false]
isChallenge ^self isProxyAuthorizedRequired or: [ self isUnauthorized ]
isClientError "Informational- Request received, continuing the process" ^self responseTypeIs: $4
isError "Informational- Request received, continuing the process" ^(self isClientError or: [ self isServerError])
isHttp10 ^self version = '1.0'
isInformationalReply "Informational - Request received, continuing the process" ^self responseTypeIs: $1
isMoved "Moved permanently/temporarily" ^(self responseEquals: '301') or: [ self responseEquals: '302']
isProxyAuthorizedRequired "Proxy Authorized Required" ^self responseEquals: '407'
isRedirectionReply "Informational- Request received, continuing the process" ^self responseTypeIs: $3
isServerError "Informational- Request received, continuing the process" ^self responseTypeIs: $5
isSuccess "Success - The action was received, understood and accepted" ^self responseTypeIs: $2
isUnauthorized "unauthorized" ^self responseEquals: '401'
isValid ^(( 'HTTP*' match: self protocol) and: [ self status > 99 and: [ self status < 600 ]])
</methods> <methods> Net.HttpResponseStatusLine <category>accessing</category>
code ^code
code: anObject code := anObject
entityType ^HttpResponse
message ^message
message: anObject message := anObject
parent ^nil
protocol (protocol isNil or: [ protocol isEmpty]) ifTrue: [ protocol := self class defaultProtocol]. ^protocol
protocol: anObject protocol := anObject
version (version isNil or: [ version isEmpty]) ifTrue: [ version := self class defaultVersion]. ^version
version: anObject version := anObject
</methods> <methods> Net.HttpResponseStatusLine <category>printing</category>
printMessageOn: aStream self code isNil ifTrue: [ ^super printOn: aStream ]. aStream nextPutAll: self code; space. self message notNil ifTrue: [aStream nextPutAll: self message]. aStream cr.
printOn: aStream self code isNil ifTrue: [ ^super printOn: aStream ]. aStream nextPutAll: self protocol, '/', self version; space; nextPutAll: self code; space. self message ifNotNil: [aStream nextPutAll: self message].
</methods> <methods> Net.HttpResponseStatusLine <category>private</category>
responseEquals: threeDigitString ^code asNumber = threeDigitString asNumber
responseTypeIs: char ^code isEmpty not ifTrue: [ code first == char ]
setCode: aString code := aString. message := self class messages at: code ifAbsent: [''].
status " Answer code as a number " ^code notNil ifTrue: [ Integer readFrom: code readStream] ifFalse: [ 0 ]
supportedVersions ^#('1.0' '1.1')
</methods> <methods> Net.HttpResponseStatusLine <category>parsing</category>
readFrom: stream | scanner | scanner := MimeScanner on: stream. protocol := scanner nextToken. scanner nextToken. version := scanner nextToken. (self supportedVersions includes: version) ifFalse: [HttpEntityError new messageText: ((#UnexpectedHTTPVersion << #net >> 'Unexpected HTTP version (<1s>)') expandMacrosWith: version); raiseSignal]. code := scanner nextToken. scanner skipWhiteSpace. message := scanner scanText.
</methods> <methods> Net.HttpResponseStatusLine <category>visiting</category>
acceptVisit: aVisitor with: argument ^aVisitor acceptResponseLine: self with: argument
</methods> <methods> Net.HttpResponseStatusLine class <category>defaults</category>
defaultMessages ^Dictionary new add: '100'->'Continue'; add: '101'->'Switching Protocols'; add: '200'->'OK'; add: '201'->'Created'; add: '202'->'Accepted'; add: '203'->'Non-Authoritative Information'; add: '204'->'No Content'; add: '205'->'Reset Content'; add: '206'->'Partial Content'; add: '300'->'Multiple Choices'; add: '301'->'Moved Permanently'; add: '302'->'Found'; add: '303'->'See Other'; add: '304'->'Not Modified'; add: '305'->'Use Proxy'; add: '307'->'Temporary Redirect'; add: '400'->'Bad Request'; add: '401'->'Unauthorized'; add: '402'->'Payment Required'; add: '403'->'Forbidden'; add: '404'->'Not Found'; add: '405'->'Method Not Allowed'; add: '406'->'Not Acceptable'; add: '407'->'Proxy Authentication Required'; add: '408'->'Request Time-out'; add: '409'->'Conflict'; add: '410'->'Gone'; add: '411'->'Length Required'; add: '412'->'Precondition Failed'; add: '413'->'Request Entity Too Large'; add: '414'->'Request-URI Too Large'; add: '415'->'Unsupported Media Type'; add: '416'->'Requested range not satisfiable'; add: '417'->'Expectation Failed'; add: '500'->'Internal Server Error'; add: '501'->'Not Implemented'; add: '502'->'Bad Gateway'; add: '503'->'Service Unavailable'; add: '504'->'Gateway Time-out'; add: '505'->'HTTP Version not supported'; yourself
defaultProtocol ^'HTTP'
defaultVersion ^'1.1'
</methods> <methods> Net.HttpResponseStatusLine class <category>instance creation</category>
code: aString ^self new setCode: aString; yourself
readFrom: stream ^self new readFrom: stream
</methods> <methods> Net.HttpResponseStatusLine class <category>accessing</category>
messages messages ifNil: [ messages := self defaultMessages]. ^messages
messages: aDictionary messages := aDictionary
</methods> <methods> Net.DigestAuthentication <category>accessing</category>
defaultAlgorithm ^defaultAlgorithm ifNil: [defaultAlgorithm := self class defaultAlgorithm]
defaultAlgorithm: aString defaultAlgorithm := aString
nextNonceCount self nonceCount: self nonceCount + 1. ^self nonceCount
nonceCount ^nonceCount ifNil: [ self resetNonceCount]
nonceCount: aNumber nonceCount := aNumber
resetNonceCount nonceCount := 0.
</methods> <methods> Net.DigestAuthentication <category>private authorization</category>
a1Value ^self authValue algorithm = 'MD5-sess' ifTrue: [self md5SessData] ifFalse: [self md5Data].
a2Value "If the 'qop' directive's value is 'auth' or is unspecified, then A2 is: A2 = Method ':' digest-uri-value If the 'qop' value is 'auth-int', then A2 is: A2 = Method ':' digest-uri-value ':' H(entity-body) " | string | string := 'GET:', self pathString. ^self H: ( self authValue qop = 'auth' ifTrue: [string] ifFalse: [string, ':', self entityHash])
cnonce: aString self authValue cnonce: aString
entityHash "Also note that if integrity protection is applied (qop=auth-int), the H(entity-body) is the hash of the entity body, not the message body - it is computed before any transfer encoding is applied by the sender and after it has been removed by the recipient. Note that this includes multipart boundaries and embedded headers in each part of any multipart content-type. " " authorizationHeader parent " ^self error: (#AuthIntNotImplemented << #net >> '<qop=auth-int> option has not been implemented in this release.')
H: data "Apply the H function (hash) to the argument as defined in section 3.2.1 The WWW-Authenticate Response Header. data <String> ascii string of data to hash ^<String> the hash value converted to a hex string [0-9a-f] " ^self LHEX: (Security.MD5 hash: data asByteArray)
LHEX: bytes "Convert bytes to the LHEX format as specified in RFC 2617, section 3.1.3 Representation of digest values bytes <ByteArray> binary value ^<String> the binery value converted into a hex string [0-9a-f] " | lookup s ws | lookup := '0123456789abcdef'. s := String new: bytes size * 2. ws := s writeStream. bytes do: [ :b | ws nextPut: (lookup at: (b bitShift: -4) + 1). ws nextPut: (lookup at: (b bitAnd: 15) + 1) ]. ^s
md5Data " If the 'algorithm' directive's value is MD5 or is unspecified, then A1 is: A1 = unq(username-value) ':' unq(realm-value) ':' passwd where passwd = < user's password > " | stream | stream := WriteStream on: String new. stream nextPutAll: self username, ':', self authValue realm, ':', self password. ^self H: stream contents
md5SessData " If the 'algorithm' directive's value is 'MD5-sess', then A1 is calculated only once - on the first request by the client following receipt of a WWW-Authenticate challenge from the server. It uses the server nonce from that challenge, and the first client nonce value to construct A1 as follows: A1 = H( unq(username-value) ':' unq(realm-value) ':' passwd ) ':' unq(nonce-value) ':' unq(cnonce-value) " | stream | md5SessData ifNil: [stream := WriteStream on: String new. stream nextPutAll: self username, ':', self authValue realm, ':', self password. md5SessData := ((self H: stream contents), ':', self authValue nonce, ':', self authValue cnonce) ]. ^md5SessData
setDigestResponse "If the 'qop' value is 'auth' or 'auth-int' KD(secret, data) = H(concat(secret, ':', data)) request-digest = <''> < KD ( H(A1), unq(nonce-value) ':' nc-value ':' unq(cnonce-value) ':' unq(qop-value) ':' H(A2) ) <''> If the 'qop' directive is not present (this construction is for compatibility with RFC 2069): request-digest = <''> < KD ( H(A1), unq(nonce-value) ':' H(A2) ) > <''> " | hashStream data | hashStream := WriteStream on: String new. hashStream nextPutAll: self authValue nonce. self authValue qop ifNotNil: [hashStream nextPut: $:. self authValue printNonceCountOn: hashStream. hashStream nextPut: $:. hashStream nextPutAll: self authValue cnonce. hashStream nextPut: $:. hashStream nextPutAll: self authValue qop]. hashStream nextPut: $:. hashStream nextPutAll: self a2Value. data := hashStream contents. ^self H: (self a1Value, ':', data)
setQopValue " 'auth'- authentication; 'auth-int' - authentication with integrity protection. Unrecognized options MUST be ignored." | qop | self authValue nc: self nextNonceCount. self authValue cnonce ifNil: [ self authValue cnonce: (self H: Timestamp now asSeconds printString) ]. (qop := self authChallenge qop detect: [ :each | each = 'auth' ] ifNone: [nil]) notNil ifTrue: [^self authValue qop: qop]. (self authValue qop detect: [ :each | each = 'auth-int' ] ifNone: [nil]) notNil ifTrue: [ " raise not implemented exception " self entityHash ]
</methods> <methods> Net.DigestAuthentication <category>select challenge</category>
selectAuthChallenge: aCollOfAuthenticateChallenge ^aCollOfAuthenticateChallenge detect: [ :auth | (self user acceptsRealm: auth realm ) and: [auth algorithm isNil or: [( 'MD5' match: auth algorithm) or: [( 'MD5-sess' match: auth algorithm)]]]] ifNone: [nil]
</methods> <methods> Net.DigestAuthentication <category>authorization</category>
acceptAuthInfoFrom: aHttpResponse | anAuthInfo v next | anAuthInfo := aHttpResponse fieldAt: 'authentication-info' ifAbsent: [^nil]. ((v := anAuthInfo value) notEmpty and: [(next := v first nextNonce) notNil ]) ifTrue: [self authValue nonce: next. self resetNonceCount ].
setNewAuthorizationValue self resetNonceCount. self authValue username: self username; realm: self authChallenge realm; nonce: self authChallenge nonce; uri: self pathString. self authChallenge opaque ifNotNil: [ self authValue opaque: self authChallenge opaque]. self authValue algorithm ifNil: [ self authValue algorithm: self defaultAlgorithm ]. self authChallenge qop ifNotNil: [self setQopValue ]. self authValue response: self setDigestResponse. self setAuthorizedState
setNextAuthorizationValueFor: header self authValue qop ifNotNil: [ "increase the nonce count" self authValue nc: self nextNonceCount; response: self setDigestResponse ]. super setNextAuthorizationValueFor: header
setPathStringFrom: aHttpRequest aHttpRequest requestLine pathString ~= self pathString ifTrue: [pathString := aHttpRequest requestLine pathString. self setNotAuthorizedState ].
</methods> <methods> Net.DigestAuthentication <category>testing</category>
canAccept: anAuthentication | ch challenge | ((challenge := anAuthentication value select: [ :val | self class acceptScheme: val scheme]) notEmpty and: [(ch := self selectAuthChallenge: challenge ) notNil and: [ch realm ~= authValue realm or: [ch isStaleTrue] ]]) ifTrue: [self setAuthChallenge: ch. ^true]. ^false
</methods> <methods> Net.DigestAuthentication class <category>defaults</category>
defaultAlgorithm ^defaultAlgorithm ifNil: [ defaultAlgorithm := self defaultAlgorithmValue ]
defaultAlgorithm: aString defaultAlgorithm := aString
defaultAlgorithmValue ^'MD5'
scheme ^'Digest'
</methods> <methods> Net.AcceptLanguageField <category>adding language</category>
addLanguage: cString self addValue: cString qValue: nil
addLanguage: cString qValue: qString self addValue: cString qValue: qString.
</methods> <methods> Net.AcceptLanguageField class <category>parsing</category>
fieldNames ^#('accept-language')
</methods> <methods> Net.AcceptLanguageField class <category>instant creation</category>
language: cString ^self language: cString qValue: nil
language: cString qValue: qString ^(self name: 'accept-language') addLanguage: cString qValue: qString; yourself
</methods> <methods> Net.CookieValue <category>initialize-release</category>
name: aString value: vString self setValueName: aString value: vString.
</methods> <methods> Net.CookieValue <category>accessing</category>
name ^self value key
nameValue ^self value value
</methods> <methods> Net.CookieValue <category>parsing</category>
addParameterNamed: valString value: parString | nm | nm := valString first = $$ ifTrue: [valString copyFrom: 2 to: valString size ] ifFalse: [ valString]. super addParameterNamed: nm value: parString
parseParameters: scanner | paramName pos nm | pos := scanner position. scanner atEnd ifFalse: [ scanner tokenizeList: [ (paramName := scanner nextToken) notNil ifTrue: [ nm := paramName first = $$ ifTrue: [paramName copyFrom: 2 to: paramName size ] ifFalse: [ paramName]. setSelectors at: nm asLowercase asSymbol ifAbsent: [scanner position: pos. ^self]. scanner skipWhiteSpace. (self validateNextToken: scanner for: paramName) ifFalse: [ InvalidHeaderField signalWith: scanner contents. ^self ]. self addParameterNamed: paramName asLowercase value: (self parseParamValueFrom: scanner). ]] separatedBy: [ pos := scanner position. scanner token == self parametersSeparator or: [scanner token == $,] ]]
</methods> <methods> Net.CookieValue <category>printing</category>
printParameter: assoc on: aStream self class scannerType printWord: '$', assoc key on: aStream. self printParameter: assoc key value: assoc value on: aStream.
</methods> <methods> Net.CookieValue <category>private-utility</category>
processUnknownParam: valString value: parString "It can be Netscape syntax: Cookie: name1=val1; name2=val2... " UnknownCookieParameter raiseFrom: valString -> parString
</methods> <methods> Net.HttpResponse <category>testing</category>
authenticateNTLMType2 | f | (f := self proxyAuthenticate detect: [:hdr | hdr isType2 ] ifNone: [nil]) isNil ifTrue: [ f := self wwwAuthenticate detect: [:hdr | hdr isType2 ] ifNone: [nil]]. ^f
canBeNTLMAuthorized ^(self proxyAuthenticate anySatisfy: [:hdr | hdr canBeNTLMAuthorized ]) or: [self wwwAuthenticate anySatisfy: [:hdr | hdr canBeNTLMAuthorized ]]
failed ^self isSuccess not
headerOnly ^self statusLine headerOnly
isClientError "Informational- Request received, continuing the process" ^self statusLine isClientError
isError "Informational- Request received, continuing the process" ^self statusLine isError
isHttp10 ^self statusLine isHttp10
isInformationalReply "Informational - Request received, continuing the process" ^self statusLine isInformationalReply
isMoved "Moved permanently/temporarily" ^self statusLine isMoved
isNTLMType2 ^(self proxyAuthenticate anySatisfy: [:hdr | hdr isType2 ]) or: [self wwwAuthenticate anySatisfy: [:hdr | hdr isType2 ]]
isProxyAuthorizedRequired "Proxy Authorized Required" ^self statusLine isProxyAuthorizedRequired
isRedirectionReply "Informational- Request received, continuing the process" ^self statusLine isRedirectionReply
isResponse ^true
isServerError "Informational- Request received, continuing the process" ^self statusLine isServerError
isSuccess ^self statusLine isSuccess
isUnauthorized "unauthorized" ^self statusLine isUnauthorized
isValid ^self statusLine isValid
successful ^self isSuccess
</methods> <methods> Net.HttpResponse <category>accessing</category>
basicProxyAuthenticationHeader ^(self fieldsAt: 'proxy-authenticate') detect: [:hdr | hdr scheme = 'basic'] ifNone: [nil]
basicWwwAuthenticationHeader ^(self fieldsAt: 'www-authenticate') detect: [:hdr | hdr scheme = 'basic'] ifNone: [nil]
code ^self statusLine code
descriptionString ^self printStatusLineMessage
messageLine ^self statusLine
messageLine: aHttpResponseStatusLine self statusLine: aHttpResponseStatusLine
protocol ^self statusLine protocol
statusLine ^statusLine
statusLine: aHttpResponseStatusLine statusLine := aHttpResponseStatusLine
version ^self statusLine version
</methods> <methods> Net.HttpResponse <category>accessing fields</category>
acceptRanges ^self fieldValueAt: 'accept-ranges'
acceptRanges: aStringOrCollection (self getFieldAt: 'accept-ranges') value: aStringOrCollection
age ^self fieldValueAt: 'age'
age: aString (self getFieldAt: 'age') value: aString
location ^self fieldValueAt: 'location'
location: aString (self getFieldAt: 'location') value: aString
proxyAuthenticate ^self fieldsAt: 'proxy-authenticate'
proxyAuthenticate: aStringOrAuthenticateChallengeField "Sets a value the parameter can be a string or instance of AuthenticateChallengeField" aStringOrAuthenticateChallengeField isString ifTrue: [ (self getFieldAt: 'proxy-authenticate') addScheme: aStringOrAuthenticateChallengeField] ifFalse: [ self removeFieldAt: 'proxy-authenticate'. self addField: aStringOrAuthenticateChallengeField]
public ^self fieldValueAt: 'public'
public: aValue (self getFieldAt: 'public') value: aValue
retryAfter ^self fieldValueAt: 'retry-after'
retryAfter: aTimestampOrStringOrArray (self getFieldAt: 'retry-after') value: aTimestampOrStringOrArray
wwwAuthenticate "Returns all AuthenticateChallengeField" ^self fieldsAt: 'www-authenticate'
wwwAuthenticate: aStringOrAuthenticateChallengeField "Sets a value the parameter can be a string or instance of AuthenticateChallengeField" aStringOrAuthenticateChallengeField isString ifTrue: [ (self getFieldAt: 'authenticate') addScheme: aStringOrAuthenticateChallengeField] ifFalse: [ self removeFieldAt: 'authenticate'. self addField: aStringOrAuthenticateChallengeField]
</methods> <methods> Net.HttpResponse <category>private</category>
log HttpClient log: [| s | s := (String new: 128) writeStream. self printHeaderOn: s. s contents] level: #HTTPServerHeader. HttpClient log: [self printString] level: #HTTPServerMessage.
statusCode: aString statusLine := HttpResponseStatusLine code: aString
</methods> <methods> Net.HttpResponse <category>printing</category>
printHeaderOn: aStream self newPrinter printMessageElement: self statusLine on: aStream. self newPrinter printMessageElement: self header on: aStream.
printStatusLineMessage | stream | stream := (String new: 32) writeStream. self statusLine printMessageOn: stream. ^stream contents
</methods> <methods> Net.HttpResponse class <category>instance creation</category>
code: aString ^self new statusCode: aString; yourself
</methods> <methods> Net.HttpPrintHandler <category>printing utilities</category>
printPreambule: aMessageBody ^true
</methods> <methods> Net.HttpPrintHandler <category>defaults</category>
dispatcherClass ^HttpDispatcher
</methods> <methods> Net.HttpPrintHandler <category>private</category>
isBinaryContent: aStream entity: anEntity ^(super isBinaryContent: aStream entity: anEntity) or: [anEntity isContentEncodingGZip ]
</methods> <methods> Net.AuthenticationValue <category>accessing</category>
basicValue ^self data
basicValue: aString ^self data: aString
ntlmValue ^self data
ntlmValue: aString ^self data: aString
realm ^realm
realm: aString ^realm := aString
scheme ^self value
scheme: aString ^self value: aString
</methods> <methods> Net.AuthenticationValue <category>testing</category>
isBasic ^self scheme asLowercase = 'basic'
isDigest ^self scheme asLowercase = 'digest'
isNTLM ^self scheme asLowercase = 'ntlm'
isNTLMType2 ^self isNTLM and: [ self ntlmValue notNil]
</methods> <methods> Net.AuthenticationValue <category>private</category>
data ^data
data: aString data := aString
</methods> <methods> Net.AuthenticationValue <category>printing</category>
printDataOn: aStream aStream nextPut: self valueSeparator. realm isNil ifTrue: [aStream nextPutAll: self data] ifFalse: [aStream nextPutAll: 'realm="', self realm, '"']
printOn: aStream super printOn: aStream. (self realm notNil or: [self data notNil]) ifTrue: [ self printDataOn: aStream ]
</methods> <methods> Net.AuthenticationValue <category>parsing</category>
parse: scanner scanner atEnd ifTrue: [ ^self]. scanner hereChar ~~ self valueSeparator ifTrue: [ scanner stepBack. ^self ]. self parseDataFrom: scanner
parseDataFrom: scanner | pos str | pos := scanner position. str := scanner nextToken. "Basic auth response has realm parameter. #nextToken will stop at $= char. If it's not 'real' parameter we need all characters " ^('realm' match: str ) ifTrue: [ scanner skipWhiteSpace. ( scanner nextToken = $=) ifFalse: [ InvalidHeaderField signalWith: scanner contents. ^self ]. realm := scanner nextToken ] ifFalse: [ scanner position: pos. data := scanner upToEnd ]
</methods> <methods> Net.HttpDispatcher <category>visiting -- double dispatching</category>
acceptMessage: aHttpEntity with: argument aHttpEntity messageLine ifNotNil: [ :line | line acceptVisit: self with: aHttpEntity]. super acceptMessage: aHttpEntity with: argument. ^aHttpEntity
acceptRequestLine: aRequestLine with: aHttpEntity self handler startRequestLine: aRequestLine with: aHttpEntity. ^aRequestLine
acceptResponseLine: aResponseStatusLine with: aHttpEntity self handler startResponseStatusLine: aResponseStatusLine with: aHttpEntity. ^aResponseStatusLine
</methods> <methods> Net.HttpProtocolInterpreter <category>cookie management</category>
addCookieTo: aRequest self getCookieAgent isNil ifTrue: [ ^nil ]. ^self cookieAgent setCookieFieldForRequest: aRequest.
cookieAgent ^cookieAgent
enableCookies enableCookies isNil ifTrue: [ enableCookies := self class enableCookieProcessing]. ^enableCookies
enableCookies: aBoolean enableCookies := aBoolean
getCookieAgent self enableCookies ifFalse: [^nil]. cookieAgent isNil ifTrue: [cookieAgent := CookieAgent new]. ^cookieAgent
registerCookiesFromResponse: aHttpResponse self getCookieAgent isNil ifTrue: [ ^nil ]. (aHttpResponse setCookieFields detect: [ :f | f shouldTerminateSession ] ifNone: [nil]) notNil ifTrue: [self terminateCookieAgent. ^nil ]. ^self cookieAgent addCookiesFrom: aHttpResponse requestUrl: self request url
terminateCookieAgent cookieAgent notNil ifTrue: [ cookieAgent terminate. cookieAgent := nil].
</methods> <methods> Net.HttpProtocolInterpreter <category>authorization</category>
acceptAuthInfoFrom: aHttpResponse authPolicy ifNotNil: [ self authPolicy acceptAuthInfoFrom: aHttpResponse ]
addAuthorizationTo: aRequest self authPolicy addAuthorizationTo: aRequest
authPolicy ^authPolicy ifNil: [ authPolicy := AuthenticationPolicy new ]
authPolicy: aHttpAuthPolicy authPolicy := aHttpAuthPolicy
proxyPassword ^self proxyUser notNil ifTrue: [ self proxyUser password] ifFalse: [nil]
proxyUser ^self proxyHost notNil ifTrue: [ self proxyHost netUser] ifFalse: [nil]
proxyUser: aNetUser self proxyHost isNil ifTrue: [ proxyHost := HostSpec new]. self proxyHost netUser: aNetUser.
proxyUsername ^self proxyUser notNil ifTrue: [ self proxyUser username] ifFalse: [nil]
realm: rString self authPolicy realm: rString
useBasicAuth self authPolicy useBasicAuth. self useProxy ifTrue: [ self authPolicy username: self proxyUsername password: self proxyPassword useProxy: true]
useNTLMAuth self authPolicy useNTLMAuth. self useProxy ifTrue: [ self authPolicy username: self proxyUsername password: self proxyPassword useProxy: true]
user ^self authPolicy user
user: aNetUser self authPolicy user: aNetUser
username: unString password: pString self authPolicy username: unString password: pString
username: aString password: pString realm: rString self authPolicy username: aString password: pString realm: rString
</methods> <methods> Net.HttpProtocolInterpreter <category>connection management</category>
close self terminateCookieAgent. self disconnect.
connect self setHostPort. self setConnection. ^super connectToHost: hostName port: portNumber timeout: timeout
connectToHost: aHostName port: aNumber timeout: tmNumber hostName := aHostName. portNumber := aNumber. timeout := tmNumber. self connect.
setConnect (self request notNil and: [connection isNil]) ifTrue: [^self streamHandlerClassFor: self request]. self request isNil ifTrue: [ ^self connection]. (self request notNil and: [connection notNil and: [(connection accepts: self request url ) not]]) ifTrue: [^self streamHandlerClassFor: self request].
setConnection (self request notNil and: [connection isNil]) ifTrue: [^self streamHandlerClassFor: self request url protocol]. self request isNil ifTrue: [ ^self connection]. (self request notNil and: [connection notNil and: [(connection accepts: self request url ) not]]) ifTrue: [self disconnect. ^self streamHandlerClassFor: self request url protocol].
setHostPort | arr | self useProxy ifTrue: [ self proxyHost isNil ifTrue: [ ^HttpException raiseSignal: (#ProxyHostIsNotDefined << #net >> 'Proxy host is not defined in Settings')] ifFalse: [(self proxyExceptions detect: [ :addr | addr match: request hostName ] ifNone: [nil]) isNil ifTrue: [hostName := self proxyHost name. portNumber := self proxyHost port]]]. hostName isNil ifTrue: [arr := request hostPortToConnect. hostName := arr first. portNumber := arr last].
streamHandlerClassFor: aString ('http' match: aString) ifTrue: [ ^connection := self netConnectionClass new ]. ('https' match: aString) ifFalse: [^HttpException raiseSignal: ((#UnsupportedProtocol1s << #net >> 'Unsupported protocol: <1s>') expandMacrosWith: aString)]. ^self useSecureConnection
</methods> <methods> Net.HttpProtocolInterpreter <category>accessing</category>
hostName ^hostName
hostName: aString hostName := aString
logAsPrintString ^logAsPrintString ifNil: [logAsPrintString := self class logAsPrintString].
logAsPrintString: aBoolean logAsPrintString := aBoolean
portNumber ^portNumber
portNumber: aNumber portNumber := aNumber
proxyExceptions ^self class proxyExceptions
proxyHost proxyHost ifNil: [ proxyHost := self class proxyHost]. ^proxyHost
proxyHost: aHostSpec proxyHost := aHostSpec
proxyHostName ^self proxyHost notNil ifTrue: [ self proxyHost name] ifFalse: [ nil ]
proxyHostPort ^(self proxyHost isNil or: [self proxyHost port isNil ]) ifTrue: [ nil ] ifFalse: [ self proxyHost port ]
redirectRequest ^Settings httpRedirectRequest
request ^request
request: anHttpRequst request := anHttpRequst
shouldChunk ^shouldChunk
shouldChunk: aBoolean shouldChunk := aBoolean
timeout ^timeout
timeout: numberOfMilliseconds timeout := numberOfMilliseconds
useProxy ^useProxy ifNil: [ useProxy := self class useProxy]
useProxy: aBoolean useProxy := aBoolean.
</methods> <methods> Net.HttpProtocolInterpreter <category>exception processing</category>
handleResponseException: ex | selector response | ^(response := ex parameter ) notNil ifTrue: [ selector := (('process', response code ), ':') asSymbol . ^(self respondsTo: selector) ifTrue: [self perform: selector with: ex ] ifFalse: [nil]] ifFalse: [nil]
process100: ex ^ex retry
process301: ex | newUrl | self redirectRequest ifFalse: [^nil]. ex parameter setCookie ifNotNil: [self registerCookiesFromResponse: ex parameter]. (#('GET' 'HEAD') includes: request method ) ifFalse: [^nil]. newUrl := self request url resolvePath: ex location. ^self request url = newUrl ifTrue: [ ex parameter ] ifFalse: [( hostName ~= newUrl host or: [portNumber ~= newUrl port ]) ifTrue: [ hostName := newUrl host. portNumber := newUrl port. self disconnect]. self request url: newUrl. self authPolicy setNotAuthorizedState. self executeAndGetResponse]
process302: ex ^self process301: ex
process401: exception "Authorization required" exception parameter setCookie ifNotNil: [self registerCookiesFromResponse: exception parameter]. ^(self authPolicy acceptChallenge: exception parameter request: self request ) ifTrue: [self executeAndGetResponse] ifFalse: [nil]
process407: exception "Proxy Authentication required" self authPolicy username: self proxyUsername password: self proxyPassword useProxy: true. ^self process401: exception
</methods> <methods> Net.HttpProtocolInterpreter <category>initialize-release</category>
readEntityFrom: stream ^self newBuilder readFrom: stream.
readFrom: stream ^self readFrom: stream onError: [ :ex | (HttpStatusLineError, HttpTimeout handles: ex) ifTrue: [ self close ]]
readFrom: stream onError: aBlock | message | ^[ message := self readEntityFrom: stream. message log. message isResponse ifTrue: [ (message isConnectionTransient or: [self request isConnectionTransient]) ifTrue: [ self close]. HttpException handleResponse: message. "response is success " self registerCookiesFromResponse: message. self acceptAuthInfoFrom: message. ] ifFalse: [ request := message ]. message ] on: HttpException do: [ :ex | aBlock value: ex. (message := self handleResponseException: ex ) isNil ifTrue: [ ex pass] ifFalse: [ message ]].
</methods> <methods> Net.HttpProtocolInterpreter <category>response</category>
readResponse ^self readFrom: self responseStream
</methods> <methods> Net.HttpProtocolInterpreter <category>ssl connection</category>
loadSecureConnection super loadSecureConnection. #{Net.HttpsConnection} valueOrDo: [URI tryToLoad: 'HTTPS']
sslConnectionClass ^#{Net.HttpsConnection} value
</methods> <methods> Net.HttpProtocolInterpreter <category>execute request</category>
executeAndGetResponse " Connect, send request, parse response and answer instance of HttpResponse class " self request isNil ifTrue: [^nil] ifFalse: [ self request useProxy: self useProxy ]. self isConnected ifFalse: [ self connect ]. self executeWithConnection: self stream. ^self readResponse
executeRequest: aRequest request := aRequest. self isConnected ifFalse: [ self connect ]. ^self executeWithConnection: self stream
</methods> <methods> Net.HttpProtocolInterpreter <category>private</category>
executeWithConnection: aConnectionStream self prepareRequestToSend. self log: self request. self newWriter writeMessage: self request on: aConnectionStream. aConnectionStream flush. ^aConnectionStream
log: message self log: [self logAsPrintString ifTrue: [message printString] ifFalse: [ | s | s := ((ByteArray new: 1024) withEncoding: #ISO8859_1) writeStream lineEndCRLF. message newWriter useGZipTransfer: self useGZipTransfer; chunkSize: self chunkSize; writeMessage: message on: s. s encodedContents asString] ] level: #HTTPClientRequest.
prepareRequestToSend self useProxy ifTrue: [ self authPolicy username: self proxyUsername password: self proxyPassword useProxy: true.]. self request useProxy: self useProxy. self addAuthorizationTo: self request. self addCookieTo: self request.
</methods> <methods> Net.HttpProtocolInterpreter <category>printing options</category>
chunkSize ^chunkSize
chunkSize: aNumber chunkSize := aNumber
newPrinter ^self request ifNotNil: [ :req | req newPrinter ]
newWriter | writer | writer := self request ifNotNil: [self request newWriter ]. self request chunkSize ifNil: [writer chunkSize: self chunkSize]. self request useGZipTransfer ifNil: [writer useGZipTransfer: self useGZipTransfer]. self request shouldChunk ifNil: [writer shouldChunk: self shouldChunk]. ^writer
useGZipTransfer ^useGZipTransfer
useGZipTransfer: aBoolean useGZipTransfer := aBoolean
</methods> <methods> Net.HttpProtocolInterpreter <category>parsing options</category>
decodeContents ^decodeContents
decodeContents: aBoolean decodeContents := aBoolean
decompressContents ^decompressContents
decompressContents: aBoolean decompressContents := aBoolean
newBuilder | b | b := self request ifNotNil: [self request newBuilder ]. self request decodeContents ifNil: [b decodeContents: self decodeContents]. self request decompressContents ifNil: [b decompressContents: self decompressContents]. ^b
</methods> <methods> Net.HttpProtocolInterpreter class <category>debugging</category>
debugLabelsAndValues ^OrderedCollection new add: ((#HTTPClientRequest << #net >> 'HTTP Client Request')->#HTTPClientRequest); add: (#HTTPServerHeader << #net >> 'HTTP Server Header')->#HTTPServerHeader; add: (#HTTPServerMessage << #net >> 'HTTP Server Message')->#HTTPServerMessage; yourself
logAsPrintString ^logAsPrintString ifNil: [logAsPrintString := self defaultLogAsPrintString]
logAsPrintString: aBoolean logAsPrintString := aBoolean
menuItemName ^(#HTTPClientMessages << #net >> 'HTTP Client Messages')
</methods> <methods> Net.HttpProtocolInterpreter class <category>cookie management</category>
enableCookieProcessing ^enableCookieProcessing isNil ifTrue: [self defaultEnableCookieProcessing] ifFalse: [enableCookieProcessing]
enableCookieProcessing: aBoolean enableCookieProcessing := aBoolean
</methods> <methods> Net.HttpProtocolInterpreter class <category>accessing</category>
keepAlive ^Settings httpKeepAlive
proxyExceptions ^Settings httpProxyExceptions
proxyHost ^Settings httpProxyHost
redirectRequest ^Settings httpRedirectRequest
useProxy ^Settings httpUseProxy
</methods> <methods> Net.HttpProtocolInterpreter class <category>instance creation</category>
readFrom: aStream ^self new readFrom: aStream
</methods> <methods> Net.HttpProtocolInterpreter class <category>class initialization</category>
initialize "self initialize." self registerToDebug.
</methods> <methods> Net.HttpProtocolInterpreter class <category>default values</category>
defaultEnableCookieProcessing ^true
defaultLogAsPrintString ^false
defaultNetConnectionValue ^HttpConnection
</methods> <methods> Net.AuthorizationField <category>accessing</category>
basicValue | s | ^(s := self basicScheme) notEmpty ifTrue: [ s first basicValue ] ifFalse: [ nil ]
digestValue | s | ^(s := self digestScheme) notEmpty ifTrue: [ s first params ] ifFalse: [ nil ]
ntlmValue | s | ^(s := self ntlmScheme) notEmpty ifTrue: [ s first ntlmValue ] ifFalse: [ nil ]
</methods> <methods> Net.AuthorizationField class <category>parsing</category>
fieldNames ^#('authorization' 'proxy-authorization')
</methods> <methods> Net.TransferEncoding <category>accessing</category>
add: aTransferEncoding self value addAll: aTransferEncoding value
canMerge ^true
</methods> <methods> Net.TransferEncoding <category>testing</category>
isChunked ^self value anySatisfy: [ :vx | 'chunked' match: vx ]
isGZipped ^self value anySatisfy: [ :vx | 'gzip' match: vx ]
</methods> <methods> Net.TransferEncoding class <category>instant creation</category>
chunkedTransfer " Answer an instance of this field representing chunked transfer encoding for Http mesages Transfer-Encoding: chunked " ^(self name: 'transfer-encoding') value: 'chunked'
gzipTransfer " Answer an instance of this field representing compressed transfer encoding for Http messages Transfer-encoding: gzip " ^(self name: 'transfer-encoding') value: 'gzip'
</methods> <methods> Net.TransferEncoding class <category>parsing</category>
fieldNames ^#( 'transfer-encoding' )
</methods> <methods> Net.AuthenticationInfoField <category>accessing</category>
valueWithParamsClass ^DigestAuthenticationValue
</methods> <methods> Net.AuthenticationInfoField class <category>parsing</category>
fieldNames ^#('authentication-info' )
</methods> <methods> Net.HttpClient <category>accessing</category>
hostName ^self clientPI hostName
hostName: aString self clientPI hostName: aString
logAsPrintString: aBoolean self clientPI logAsPrintString: aBoolean
portNumber ^self clientPI portNumber
portNumber: aNumber self clientPI portNumber: aNumber
protocol ^protocol ifNil: [protocol := request notNil ifTrue: [ request protocol ] ifFalse: [self class protocol ] ]
protocol: aString protocol := aString
proxyHost ^self clientPI proxyHost
proxyHost: aHostSpec self clientPI proxyHost: aHostSpec
proxyHostName ^self clientPI proxyHostName
proxyHostPort ^self clientPI proxyHostPort
request ^request
requestClass ^HttpRequest
timeout ^self clientPI timeout
timeout: numberOfMilliseconds self clientPI timeout: numberOfMilliseconds
useProxy ^self clientPI useProxy
useProxy: aBoolean self clientPI useProxy: aBoolean.
</methods> <methods> Net.HttpClient <category>authorization</category>
authPolicy ^self clientPI authPolicy
authPolicy: aHttpAuthPolicy self clientPI authPolicy: aHttpAuthPolicy
proxyPassword ^self clientPI proxyPassword
proxyUser ^self clientPI proxyUser
proxyUser: aNetUser self clientPI proxyUser: aNetUser
proxyUsername ^self clientPI proxyUsername
realm: rString self authPolicy realm: rString
useBasicAuth self clientPI useBasicAuth.
useNTLMAuth self clientPI useNTLMAuth.
user ^self authPolicy user
user: aNetUser self authPolicy user: aNetUser
username: unString password: pString self authPolicy username: unString password: pString
username: aString password: pString realm: rString self authPolicy username: aString password: pString realm: rString
</methods> <methods> Net.HttpClient <category>cookie management</category>
addCookieToRequest ^self clientPI addCookieTo: request.
cookieAgent ^self clientPI cookieAgent
enableCookies ^self clientPI enableCookies
enableCookies: aBoolean self clientPI enableCookies: aBoolean
registerCookiesFromResponse: aHttpResponse ^self clientPI registerCookiesFromResponse: aHttpResponse
terminateCookieAgent self clientPI terminateCookieAgent
</methods> <methods> Net.HttpClient <category>commands</category>
delete: urlString request := (self requestClass delete: urlString ). ^self executeAndGetResponse
get: urlString "The GET method means retrieve whatever information (in the form of an entity ) is identified by the urlString" "Returns an instance of HttpResponse if succeed or exception" request := (self requestClass get: urlString ). ^self executeAndGetResponse
headers: urlString "The HEAD method is identical to GET except that the server must not return a message body in the response" "Returns an instance of HttpResponse if succeed or exception" request := (self requestClass headers: urlString ). ^self executeAndGetResponse
post: urlString contents: aString " The POST method is used to request that the destination server accept the specified aString as a new subordinate of the resource identified by the urlString Returns an instance of HttpResponse if succeed or exception" request := (self requestClass post: urlString ). request contents: aString. ^self executeAndGetResponse
put: urlString contents: aString "The PUT method requests that the specified aString be stored under the supplied urlString. Returns an instance of HttpResponse if succeed or exception" request := (self requestClass put: urlString ). request contents: aString. ^self executeAndGetResponse
</methods> <methods> Net.HttpClient <category>connection management</category>
close self clientPI close
connect self clientPI streamHandlerClassFor: self protocol. ^self clientPI connect
disconnect super disconnect. protocol := nil
keepAlive keepAlive isNil ifTrue: [ keepAlive := self class keepAlive]. ^keepAlive
keepAlive: aBoolean keepAlive := aBoolean
</methods> <methods> Net.HttpClient <category>streams -- guarded</category>
readStreamCmd: commandString url: url do: aBlock " Connect, evaluate block, ensure disconnect, answer block evaluation result " ^self executeRequest: (self requestClass method: commandString url: url asURI) do: aBlock
</methods> <methods> Net.HttpClient <category>initialize-release</category>
initialize super initialize. self clientPI timeout: self defaultTimeout.
</methods> <methods> Net.HttpClient <category>private -- command interface</category>
executeWithConnection: aConnectionStream "the method is used for debugging " self prepareRequestToSend. self clientPI request: request. ^self clientPI executeWithConnection: aConnectionStream
prepareRequestToSend self keepAlive notNil ifTrue: [self keepAlive ifTrue: [ request keepAlive: true]. (self keepAlive not and: [ request keepAlive not ]) ifTrue: [ request keepAlive: false] ifFalse: [ request keepAlive: true ]].
privateExecuteRequest self prepareRequestToSend. ^self clientPI executeRequest: request
request: aReq request := aReq. self clientPI request: aReq
</methods> <methods> Net.HttpClient <category>low-level command interface</category>
executeAndGetResponse " Connect, send request, parse response and answer instance of HttpResponse class " self request ifNil: [^nil]. self executeRequestDo: nil. ^self getResponse
executeRequest: aRequest " Connect, send request and answer HttpResponse " request := aRequest. ^self executeAndGetResponse
executeRequest: aRequest do: aBlock " Connect, send request and pass connection to specified block " request := aRequest. ^self executeRequestDo: aBlock
executeRequestDo: aBlock " Connect, send request and pass connection to specified block " | streamx | streamx := self privateExecuteRequest. ^aBlock ifNotNil: [ aBlock value: streamx ]
getResponse ^self clientPI readResponse
</methods> <methods> Net.HttpClient <category>utilities</category>
getUserAndPasswordDialogFor: response | dialog spec result msg userx passwordx| dialog := SimpleDialog new. spec := (dialog class interfaceSpecFor: #emptySpec). dialog initializeBuilderFor: nil. dialog builder add: spec window. dialog builder add: spec component. dialog initializeWindowFor: nil. msg := response descriptionString isNil ifTrue: [(#TheServerRequiresUserPassword << #net >> 'The server requires a user and password to see this resource.')] ifFalse: [response descriptionString]. dialog setInitialGap. dialog addMessage: msg centered: false. dialog addGap: 8. dialog addMessage: (#UserNameC << #net >> 'User Name:') centered: false. dialog addGap: 4. dialog addTextLine: (userx := String new asValue). dialog addGap: 8. dialog addMessage: (#PasswordC << #net >> 'Password:') centered: false. dialog addGap: 4. dialog addTextLine: (passwordx := String new asValue) type: #password. dialog addGap: 8. dialog addOK: [true]. dialog addGap: 6. dialog preOpen. dialog builder window maximumSize: Screen default bounds width @ dialog builder window displayBox height. dialog builder window minimumSize: 150 @ dialog builder window displayBox height. dialog builder openDialogWithExtent: dialog builder window displayBox extent. result := dialog accept value ifTrue: [self class encodeUser: userx value password: passwordx value] ifFalse: [nil]. ^result
</methods> <methods> Net.HttpClient <category>streams -- unguarded</category>
readStreamCmd: commandString url: url " Connect, send request and answer http connection stream " request := self requestClass method: commandString url: url asURI. ^self privateExecuteRequest
</methods> <methods> Net.HttpClient <category>printing options</category>
chunkSize ^self clientPI chunkSize
chunkSize: aNumber ^self clientPI chunkSize: aNumber
doChunk self clientPI shouldChunk: true
doNotChunk self clientPI shouldChunk: false
useGZipTransfer ^self clientPI useGZipTransfer
useGZipTransfer: aBoolean self clientPI useGZipTransfer: aBoolean
</methods> <methods> Net.HttpClient <category>parsing options</category>
decodeContents: aBoolean self clientPI decodeContents: aBoolean
decompressContents: aBoolean self clientPI decompressContents: aBoolean
</methods> <methods> Net.HttpClient class <category>constants</category>
description ^(#HTTPServer << #net >> 'HTTP server') asString
serverType ^#HTTP
</methods> <methods> Net.HttpClient class <category>accessing</category>
autoloadHttps ^Settings httpsAutoload
autoloadHttps: aBoolean Settings httpsAutoload: aBoolean
keepAlive ^Settings httpKeepAlive
protocol ^Protocol ifNil: [ Protocol := self defaultProtocolValue ]
protocol: aString Protocol := aString.
proxyExceptions ^Settings httpProxyExceptions
proxyHost ^Settings httpProxyHost
useProxy ^Settings httpUseProxy
</methods> <methods> Net.HttpClient class <category>utilities</category>
disableProxy ^self netSettings httpUseProxy: false
enableProxy ^self netSettings httpUseProxy: true
httpUsername: username password: password (username notNil and: [ password notNil]) ifTrue: [ Settings httpUser: (NetUser username: username password: password) ].
proxyHost: host port: port self proxyHost: host port: port userid: nil password: nil
proxyHost: host port: port userid: username password: password | intPort hostSpec | host isString ifFalse: [self error: (#ProxyHostNameMustBeString << #net >> 'Proxy host name must be a string')]. intPort := port isCharacters ifTrue: [Integer readFrom: port readStream] ifFalse: [port]. intPort isInteger ifFalse: [self error: (#ProxyPortMustBeAnInteger << #net >> 'Proxy port must be an integer')]. hostSpec := (HostSpec new name: host; port: intPort; type: 'http'; yourself). (username notNil and: [ password notNil]) ifTrue: [ hostSpec netUser: (NetUser username: username password: password)]. " set http proxy Settings " Settings httpProxyHost: hostSpec.
setKeepAlive Settings httpKeepAlive: true
</methods> <methods> Net.HttpClient class <category>instance creation</category>
loginToHost: aHostName asUser: userString withPassword: passwdString self shouldNotImplement
loginToHost: aHostName port: aNumber asUser: userString withPassword: passwdString self shouldNotImplement
</methods> <methods> Net.HttpClient class <category>debugging</category>
debugLabelsAndValues ^OrderedCollection new add: ((#HTTPClientRequest << #net >> 'HTTP Client Request')->#HTTPClientRequest); add: (#HTTPServerHeader << #net >> 'HTTP Server Header')->#HTTPServerHeader; add: (#HTTPServerMessage << #net >> 'HTTP Server Message')->#HTTPServerMessage; yourself
menuItemName ^(#HTTPClientMessages << #net >> 'HTTP Client Messages')
</methods> <methods> Net.HttpClient class <category>class initialization</category>
initialize "self initialize" super initialize. self registerToDebug. HeaderField resetRegistry.
</methods> <methods> Net.HttpClient class <category>default values</category>
defaultProtocolInterpreterClassValue ^HttpProtocolInterpreter
defaultProtocolValue ^'http'
</methods> <methods> Net.HttpClient class <category>cookie management</category>
enableCookieProcessing ^self defaultProtocolInterpreterClass enableCookieProcessing
enableCookieProcessing: aBoolean self defaultProtocolInterpreterClass enableCookieProcessing: aBoolean
</methods> <methods> Net.HttpClient class <category>commands</category>
get: urlString ^self clientDo: [ :client | client get: urlString]
headers: urlString ^self clientDo: [ :client | client headers: urlString]
post: urlString contents: aString ^self clientDo: [ :client | client post: urlString contents: aString]
</methods> <methods> Net.HttpClient class <category>private</category>
clientDo: aBlock | client | client := self new. ^[ aBlock value: client ] ensure: [ client ifNotNil: [ client close]]
</methods> <methods> Net.ChunkedStream <category>accessing</category>
binary
text
</methods> <methods> Net.ChunkedStream <category>initialize-release</category>
initializeOn: aStream stream := aStream. stream binary.
</methods> <methods> Net.ChunkedStream <category>testing</category>
isReadable ^self subclassResponsibility
isWritable ^self subclassResponsibility
</methods> <methods> Net.ChunkedStream <category>private</category>
contentsSpecies ^ByteArray
signalError: aString HttpException raiseSignal: aString
</methods> <methods> Net.ChunkedReadStream <category>status</category>
close stream close.
</methods> <methods> Net.ChunkedReadStream <category>initialize-release</category>
reset buffer := nil. position := nil.
</methods> <methods> Net.ChunkedReadStream <category>testing</category>
atEnd position = readLimit ifTrue: [ self nextChunk ]. ^readLimit = 0
isReadable ^true
isWritable "Answer whether the stream implements #nextPut:." ^false
</methods> <methods> Net.ChunkedReadStream <category>private</category>
nextChunk self nextChunkSize > 0 ifTrue: [position := 0. [buffer := stream next: readLimit ] on: Stream incompleteNextCountSignal do: [:ex | self signalError: (#IncompleteChunkCount <<#netclients >> 'Incomplete chunk count'). ^ex return ]. (stream next = self lineEnd first ) ifFalse: [ self signalError: (#WrongChunkFormat <<#netclients >> 'Wrong chunk format')]. stream peekFor: self lineEnd last]
nextChunkSize readLimit := Integer readFrom: (stream upTo: self lineEnd first ) asString readStream radix: 16. self lineEnd size > 1 ifTrue: [stream peekFor: self lineEnd last ]. readLimit = 0 ifTrue: [self reset]. ^readLimit
</methods> <methods> Net.ChunkedReadStream <category>accessing</category>
next buffer ifNil: [ self nextChunk]. self atEnd ifTrue: [^self pastEnd]. position := position + 1. ^buffer at: position
next: aNumber | line | self atEnd ifTrue: [^self pastEnd]. line := self contentsSpecies new: aNumber. 1 to: aNumber do: [ :ind | line at: ind put: self next]. ^line
</methods> <methods> Net.BasicAuthentication <category>authorization</category>
setNewAuthorizationValue self authValue basicValue: (self class encodeUser: self username password: self password). self setAuthorizedState
</methods> <methods> Net.BasicAuthentication class <category>defaults</category>
scheme ^'Basic'
</methods> <methods> Net.BasicAuthentication class <category>utilities</category>
encodeUser: username password: password | uncodedValue result | uncodedValue := (username, ':', password) asByteArrayEncoding: #ISO8859_1. result := (String new: 32) writeStream. MimeScanner encode: uncodedValue readStream asBase64To: result. ^result contents
</methods> <methods> Net.CookieAgent <category>utilities</category>
cookiesAt: anUrl ^self registry at: (self keyFrom: anUrl) ifAbsentPut: [ OrderedCollection new ].
setCookieFieldForRequest: aHttpRequest | f | (f := self cookieFieldForUrl: aHttpRequest url ) notNil ifTrue: [aHttpRequest cookie: f ]. ^f
</methods> <methods> Net.CookieAgent <category>testing limits</category>
exceedNumberBytesPerCookie: aSetCookieValue aSetCookieValue printString size > self class numberBytesPerCookie ifTrue: [ RegistryLimitationExc raiseRequestFrom: (#exceedNumberBytesPerCookie << #net >> 'Exceed number bytes per cookie <1s>' expandMacrosWith: aSetCookieValue printString) ]. ^false
exceedNumberEntries self exceedNumberEntries: self registry
exceedNumberEntries: aRegistry | size | size := 0. aRegistry values do: [ :vx | size := size + vx size ]. size > self class numberEntries ifTrue: [ RegistryLimitationExc raiseRequestFrom: (#exceedNumberEntries << #net >> 'Exceed total cookie number') ]. ^false
exceedNumberEntriesPerServer: aString self exceedNumberEntriesPerServer: aString registry: self registry
exceedNumberEntriesPerServer: aString registry: aRegistry | coll | coll := aRegistry at: aString ifAbsent: [ ^false ]. coll size > self class numberEntriesPerServer ifTrue: [ RegistryLimitationExc raiseRequestFrom: (#exceedNumberEntriesPerServer << #net >> 'Exceed number entries per server <1s>' expandMacrosWith: aString) ]. ^false
shouldUpdateServer: aString ^(self class serversCacheCookiesFrom isEmpty or: [ self class serversCacheCookiesFrom notEmpty and: [ self class serversCacheCookiesFrom includes: aString ]]).
testCookieBytesLimit: aSetCookieValue self enableLimits ifTrue: [ self exceedNumberBytesPerCookie: aSetCookieValue]
testRegistryAndServerLimits: aString self enableLimits ifTrue: [ self exceedNumberEntriesPerServer: aString. self exceedNumberEntries ].
</methods> <methods> Net.CookieAgent <category>managing cookies</category>
getValidCookieValuesFrom: aCookieCollection requestUrl: anUrl | coll | coll := OrderedCollection new. aCookieCollection do: [ :cx | cx value do: [ :vx | (self rejectCookieValue: vx requestUrl: anUrl) ifFalse: [self testCookieBytesLimit: vx. coll add: vx]]]. ^coll
registryAdd: aCollection forUrl: anUrl | setCookiesColl cookie k | aCollection isEmpty ifTrue: [^nil]. setCookiesColl := self registry at: (k := self keyFrom: anUrl) ifAbsentPut: [ OrderedCollection new ]. aCollection do: [ :newCookie | (cookie := setCookiesColl detect: [ :cx | cx = newCookie ] ifNone: [ nil]) notNil ifTrue: [ setCookiesColl remove: cookie]]. setCookiesColl addAll: aCollection. self testRegistryAndServerLimits: k. ^setCookiesColl
rejectCookieValue: aSetCookieValue requestUrl: anUrl aSetCookieValue isExpired ifTrue: [self removeExpiredCookieValue: aSetCookieValue requestUrl: anUrl. ^true]. ^(self validateDomain: aSetCookieValue domain host: anUrl host) not or: [ (self validatePathFrom: aSetCookieValue path path: anUrl pathString ) not or: [(self validatePort: aSetCookieValue port port: anUrl port ) not ]]
removeExpiredCookieValue: aSetCookieValue requestUrl: anUrl | vx coll | coll := self registry at: ( self keyFrom:anUrl) ifAbsent: [^nil ]. vx := coll detect: [ :cx | cx value key = aSetCookieValue value key] ifNone: [ nil]. vx ifNotNil: [coll remove: vx ].
validateDomain: aCookieDomain host: aHostString | reqHost cookieDomain ind | reqHost := aHostString asLowercase. aCookieDomain notNil ifTrue: [cookieDomain := aCookieDomain asLowercase. (cookieDomain at: 1) ~= $. ifTrue: [ cookieDomain := '.', cookieDomain]. "The request-host has the form HD, where D is value of the domain attribute" (( '*', cookieDomain) match: reqHost) ifFalse: [ ^false ]. ind := reqHost indexOfSubCollection: cookieDomain startingAt: 1. "The request-host contains embedded dots or the domain attribute contains no embedded dots" (((reqHost copyFrom: 1 to: ind - 1 ) includes: $.) or: [ ('.*.*' match: cookieDomain) not and: [ ('.local' match: cookieDomain) not ]]) ifTrue: [^false]. ]. ^true.
validatePathFrom: aCookiePath path: requestPath aCookiePath notNil ifTrue: ["the value for the path attribute has to be a prefix of the request url " (( aCookiePath, '*' ) match: requestPath ) ifFalse: [ ^false ]]. ^true
validatePort: aCookiePort port: portNumber "the request-port is not in the port attribute" ^(aCookiePort isNil or: [aCookiePort isKindOf: Boolean]) or: [ aCookiePort notNil and: [ (aCookiePort isKindOf: Collection) and: [(aCookiePort includes: portNumber) ]]]
</methods> <methods> Net.CookieAgent <category>converting</category>
accept: anUrl for: aSetCookieValue key: keyUrl ^(aSetCookieValue isNotExpired and: [ (self cookieDomain: aSetCookieValue domain accept: anUrl host) and: [(self cookiePath: aSetCookieValue path accept: anUrl pathString) and: [self cookiePort: aSetCookieValue port accept: anUrl port from: keyUrl ]]])
cookieDomain: aSetCookieDomain accept: aString ^aSetCookieDomain isNil or: [ aSetCookieDomain notNil and: ['*', aSetCookieDomain asLowercase match: aString asLowercase]]
cookieFieldForUrl: anUrl "Creates 'Cookie' field for the specified url from registered 'Set-Cookie' or 'Set-Cookie2' fields " | coll sc xInd yInd f | coll := OrderedCollection new. self registry keysAndValuesDo: [ :key :value | value do: [ :vx | (self accept: anUrl for: vx key: key) ifTrue: [coll add: vx ]]]. coll isEmpty ifTrue: [ ^nil ]. sc := SortedCollection withAll: coll sortBlock: [ :x : y | xInd := x path notNil ifTrue: [x path occurrencesOf: $/ ] ifFalse: [0]. yInd := y path notNil ifTrue: [y path occurrencesOf: $/ ] ifFalse: [0]. xInd >= yInd ]. f := sc first isRFCStyle ifTrue: [CookieField newRfc ] ifFalse: [ CookieField newNetscape ]. f value: (sc collect: [ :cx | cx asCookie ]). ^f
cookiePath: aCookiePath accept: requestPath ^aCookiePath isNil or: [aCookiePath notNil and: [( aCookiePath, '*' ) match: requestPath ]]
cookiePort: aSetCookiePort accept: aNumber from: hostPort aSetCookiePort isNil ifTrue: [^true]. ^(aSetCookiePort isKindOf: Boolean) ifTrue: [(hostPort tokensBasedOn: $: ) last asNumber = aNumber] ifFalse: [aSetCookiePort isEmpty ifTrue: [ true ] ifFalse: [aSetCookiePort includes: aNumber ]]
</methods> <methods> Net.CookieAgent <category>accessing</category>
cacheCookies ^cacheCookies isNil ifTrue: [cacheCookies := self class cacheCookies] ifFalse: [ cacheCookies ]
cacheCookies: aBoolean cacheCookies := aBoolean
classRegistry ^self class registry
classRegistryAt: aServerString put: aCollection self classRegistry at: aServerString put: aCollection. self enableLimits ifTrue: [ self exceedNumberEntriesPerServer: aServerString registry: self classRegistry. self exceedNumberEntries: self classRegistry ].
enableLimits ^enableLimits isNil ifTrue: [ enableLimits := self class enableLimits] ifFalse: [ enableLimits ]
enableLimits: aBoolean enableLimits := aBoolean
keyFrom: anUrl ^self class keyFrom: anUrl
registry ^registry
useCachedCookies ^useCachedCookies isNil ifTrue: [ useCachedCookies := self class useCachedCookies] ifFalse: [ useCachedCookies ]
useCachedCookies: anObject useCachedCookies := anObject
</methods> <methods> Net.CookieAgent <category>initialize-release</category>
addCookiesFrom: aHttpResponse requestUrl: anUrl self setCacheCookieFrom: aHttpResponse. ^self registryAdd: (self getValidCookieValuesFrom: aHttpResponse setCookieFields requestUrl: anUrl) forUrl: anUrl.
initialize registry := Dictionary new. self start.
start "Starts cookie session" | vColl | self class useCachedCookies ifTrue: [ self classRegistry keysAndValuesDo: [ :key :values | vColl := values select: [ :vx | vx isNotExpired ]. self registry at: key put: vColl copy ]].
terminate "Terminates cookie session. Saves session cookies to the class registry" | coll vColl newColl | self cacheCookies ifTrue: [ self registry keysAndValuesDo: [ :key :values | (self shouldUpdateServer: key) ifTrue: [vColl := values select: [ :vx | vx shouldNotBeDiscard and: [ vx isNotExpired ] ]. (coll := self classRegistry at: key ifAbsent: [ nil ]) isNil ifTrue: [ self classRegistryAt: key put: vColl ] ifFalse: [ newColl := OrderedCollection new: ( coll size + vColl size). coll do: [ :vclass | vColl detect: [ :vx | vx = vclass ] ifNone: [ newColl add: vclass]]. newColl addAll: vColl. self classRegistryAt: key put: newColl ]]]].
</methods> <methods> Net.CookieAgent <category>caching</category>
setCacheCookieFrom: aHttpResponse | noCache | aHttpResponse cacheControl notNil ifTrue: [noCache := aHttpResponse cacheControl noCache. (noCache isKindOf: Boolean) ifTrue: [ ^nil ]. ('set-cookie2' match: noCache first ) ifTrue: [ self cacheCookies: false ]].
</methods> <methods> Net.CookieAgent class <category>accessing</category>
cookiesAt: anUrl ^self registry at: (self keyFrom: anUrl) ifAbsentPut: [ OrderedCollection new ].
keyFrom: anUrl ^anUrl host, ':', anUrl port printString
registry Registry ifNil: [ self resetRegistry ]. ^Registry
resetRegistry Registry := Dictionary new
</methods> <methods> Net.CookieAgent class <category>instance creation</category>
addCookiesFrom: aHttpEntity requestUrl: anUrl ^self new addCookiesFrom: aHttpEntity requestUrl: anUrl; yourself
new ^super new initialize
</methods> <methods> Net.CookieAgent class <category>defaults</category>
defaultCacheCookies ^false
defaultEnableLimits ^false
defaultNumberBytesPerCookie ^4096
defaultNumberEntries ^300
defaultNumberEntriesPerServer ^20
defaultServersCacheCookiesFrom ^OrderedCollection new
defaultUseCachedCookies ^false
</methods> <methods> Net.CookieAgent class <category>accessing settings</category>
cacheCookies ^CacheCookies isNil ifTrue: [self defaultCacheCookies] ifFalse: [CacheCookies]
cacheCookies: aBoolean CacheCookies := aBoolean
enableLimits ^EnableLimits isNil ifTrue: [self defaultEnableLimits] ifFalse: [EnableLimits]
enableLimits: aBoolean EnableLimits := aBoolean
numberBytesPerCookie ^NumberBytesPerCookie isNil ifTrue: [NumberBytesPerCookie := self defaultNumberBytesPerCookie ] ifFalse: [NumberBytesPerCookie]
numberBytesPerCookie: aNumber NumberBytesPerCookie := aNumber
numberEntries ^NumberEntries isNil ifTrue: [NumberEntries := self defaultNumberEntries] ifFalse: [NumberEntries]
numberEntries: aNumber NumberEntries := aNumber
numberEntriesPerServer ^NumberEntriesPerServer isNil ifTrue: [NumberEntriesPerServer := self defaultNumberEntriesPerServer] ifFalse: [NumberEntriesPerServer]
numberEntriesPerServer: aNumber NumberEntriesPerServer := aNumber
serversCacheCookiesFrom ^ServersCacheCookiesFrom isNil ifTrue: [ServersCacheCookiesFrom := self defaultServersCacheCookiesFrom] ifFalse: [ServersCacheCookiesFrom]
serversCacheCookiesFrom: aCollection ServersCacheCookiesFrom := aCollection
useCachedCookies ^UseCachedCookies isNil ifTrue: [self defaultUseCachedCookies] ifFalse: [UseCachedCookies]
useCachedCookies: aBoolean UseCachedCookies := aBoolean
</methods> <methods> Net.ManOptField <category>accessing</category>
addNamespace: urlString id: idNumber | valWithParams | valWithParams := ValueWithParams newWithSeparators: self separators. valWithParams value: urlString. idNumber notNil ifTrue: [valWithParams paramAt: 'ns' put: idNumber]. self value add: valWithParams. ^valWithParams
id ^self element paramAt: 'ns'
id: idNumber self element paramAt: 'ns' put: idNumber
namespace ^self element value
namespace: urlString self element value: urlString
namespace: urlString id: idNumber self namespace: urlString; id: idNumber
</methods> <methods> Net.ManOptField <category>queries</category>
idForNamespace: urlString ^self idForNamespace: urlString ifAbsent: [nil]
idForNamespace: urlString ifAbsent: aBlock | param | param := self value detect: [ :ea | ea value = urlString] ifNone: [ nil]. ^param notNil ifTrue: [ param paramAt: 'ns'] ifFalse: [ aBlock value]
namespaceForId: idNumber ^self namespaceForId: idNumber ifAbsent: [nil]
namespaceForId: idNumber ifAbsent: aBlock | param | param := self value detect: [ :ea | (ea paramAt: 'ns') = idNumber] ifNone: [ nil]. ^param notNil ifTrue: [ param value ] ifFalse: [ aBlock value ]
namespaceMap |dict| dict := Dictionary new. self value do: [ :ea | dict at: ea value put: (ea paramAt: 'ns')]. ^dict
namespaceMapAt: nsString ^self namespaceMapAt: nsString ifAbsent: nil
namespaceMapAt: nsString ifAbsent: aBlock ^self namespaceMap at: nsString ifAbsent: [aBlock].
namespaceMapKeyAtValue: idString ^self namespaceMapKeyAtValue: idString ifAbsent: nil
namespaceMapKeyAtValue: idString ifAbsent: aBlock self namespaceMap keysAndValuesDo: [:aKey :aValue | idString = aValue ifTrue: [^aKey]]. ^aBlock value
removeId: idString self value removeAllSuchThat: [ :valWithParams | (valWithParams paramAt: 'ns') = idString ]
</methods> <methods> Net.ManOptField class <category>parsing</category>
fieldNames ^#('man' 'opt' 'c-man' 'c-opt' )
</methods> <methods> Net.ManOptField class <category>instant creation</category>
field: aFieldName namespace: nsString id: idString ^(self name: aFieldName) addNamespace: nsString id: idString; yourself
</methods> <methods> Net.CacheControl <category>accessing</category>
addMustRevalidate "must-revalidate" self addDirective: 'must-revalidate'->nil
addNoCache " 'no-cache' [ '= <''> 1#field-name <''> ] " self addDirective: 'no-cache'->nil
addNoStore "no-store" self addDirective: 'no-store'->nil
addNoTransform "no-transform" self addDirective: 'no-transform'->nil
addOnlyIfCached "only-if-cached " self addDirective: 'only-if-cached'->nil
addPrivate "private [ ''='' <''> 1#field-name <''> ]" self addDirective: 'private'->nil
addProxyRevalidate "proxy-revalidate" self addDirective: 'proxy-revalidate'->nil
addPublic "public " self addDirective: 'public'->nil
maxAge "'max-age' ''='' delta-seconds " ^self detectValueFor: 'max-age'
maxAge: aNumber "'max-age' ''='' delta-seconds " self addDirective: 'max-age'->aNumber
maxStale "'max-stale' ''='' delta-seconds " ^self detectValueFor: 'max-stale'
maxStale: aNumber "'max-stale' ''='' delta-seconds " self addDirective: 'max-stale'->aNumber
minFresh "'min-fresh' ''='' delta-seconds " ^self detectValueFor: 'min-fresh'
minFresh: aNumber "'min-fresh' ''='' delta-seconds " self addDirective: 'min-fresh'->aNumber
mustRevalidate "must-revalidate" ^self anySatisfy: 'must-revalidate'
noCache " 'no-cache' [ '= <''> 1#field-name <''> ] " ^self detectValueFor: 'no-cache'
noCache: aCollOfStringsOrNil " 'no-cache' [ '= <''> 1#field-name <''> ] " self addDirective: 'no-cache'->aCollOfStringsOrNil
noStore "no-store" ^self anySatisfy: 'no-store'
noTransform "no-transform" ^self anySatisfy: 'no-transform'
onlyIfCached "only-if-cached " ^self anySatisfy: 'only-if-cached'
private "private [ ''='' <''> 1#field-name <''> ]" ^self detectValueFor: 'private'
private: aCollOfStringsOrNil "private [ ''='' <''> 1#field-name <''> ]" self addDirective: 'private'->aCollOfStringsOrNil
proxyRevalidate "proxy-revalidate" ^self anySatisfy: 'proxy-revalidate'
public "public " ^self anySatisfy: 'public'
values ^value isNil ifTrue: [ value := OrderedCollection new] ifFalse: [ value ]
</methods> <methods> Net.CacheControl <category>private</category>
anySatisfy: aString ^self values anySatisfy: [ :val | val key asLowercase = aString ]
detectValueFor: aString | v | ^(v := self value detect: [ :val | val key asLowercase = aString ] ifNone: [nil]) notNil ifTrue: [ v value notNil ifTrue: [ v value] ifFalse: [true]] ifFalse: [false]
</methods> <methods> Net.CacheControl <category>printing</category>
printParameters: anObject on: aStream aStream nextPut: $=. (anObject isKindOf: OrderedCollection) ifTrue: [aStream nextPut: $". anObject do: [ :param | aStream nextPutAll: param] separatedBy: [aStream nextPut: $, ]. aStream nextPut: $" ] ifFalse: [anObject respondsToArithmetic ifTrue: [anObject printOn: aStream] ifFalse: [ aStream nextPutAll: anObject]]
printValueOn: aStream self values do: [ :val | aStream nextPutAll: val key. val value notNil ifTrue: [self printParameters: val value on: aStream]] separatedBy: [aStream nextPut: self separator]. aStream cr.
</methods> <methods> Net.CacheControl <category>parsing</category>
parseItem: aString | scanner token | scanner := self scannerOn: aString readStream. token := scanner nextToken. ^(scanner hereChar == $= ) ifTrue: [token ->(self parseParameters: scanner key: token asLowercase)] ifFalse: [token->nil]
parseParameters: scanner key: aString | paramColl newScanner t | paramColl := OrderedCollection new. scanner next. scanner nextToken. ^scanner tokenType == #quotedText ifTrue: [newScanner := scanner newSize: scanner token size startingAt: (scanner position - scanner token size - 1). newScanner tokenizeList: [ t := newScanner nextToken. paramColl add: t] separatedBy: [ newScanner token == self separator ]. scanner next. paramColl] ifFalse: [(scanner tokenType == #token and: [ self isDeltaSeconds: aString]) ifTrue: [ scanner token asNumber] ifFalse: [scanner token]]
</methods> <methods> Net.CacheControl <category>directives</category>
addDirective: anAssocOrString | val | val := (anAssocOrString isString ifTrue: [ anAssocOrString->nil] ifFalse: [anAssocOrString]). self removeDirective: val key. self values add: val
directiveAt: aString ^self detectValueFor: aString
removeDirective: aString self values removeAllSuchThat: [ :v | v key = aString ].
</methods> <methods> Net.CacheControl <category>testing</category>
isDeltaSeconds: aString ^#( 'max-age' 'max-stale' 'min-fresh' ) includes: aString
</methods> <methods> Net.CacheControl class <category>parsing</category>
fieldNames ^#('cache-control')
</methods> <methods> Net.CookieField <category>accessing</category>
valueWithParamsClass ^CookieValue
version ^version
version: aNumber version := aNumber
</methods> <methods> Net.CookieField <category>parsing</category>
doParse: scanner | tokens position list valx | position := scanner position. tokens := self doPrivateParse: scanner. (tokens first asLowercase = '$version' and: [ (tokens at: 2) = $= ]) ifTrue: ["RFC2965 style: the first attribute has to be $version " version := tokens last asNumber] ifFalse: ["Netscape" scanner position: position. version := nil ]. list := OrderedCollection new: 5. [scanner atEnd ] whileFalse: [valx := self valueWithParamsClass newWithSeparators: self separators. valx readFrom: scanner. list add: valx ]. ^list
</methods> <methods> Net.CookieField <category>private</category>
doPrivateParse: scanner | str | str := scanner scanUntil: [ scanner hereChar == self valueSeparator or: [ scanner hereChar == self groupSeparator] ]. ^self tokenize: (self scannerOn: str readStream).
</methods> <methods> Net.CookieField <category>printing</category>
printValueOn: aStream version notNil ifTrue: [aStream nextPutAll: '$version=', self version printString. aStream nextPut: self valueSeparator]. self value notNil ifTrue: [version notNil ifTrue: [ aStream crtab]. self value do: [ :param | param printOn: aStream] separatedBy: [aStream nextPut: self groupSeparator. version notNil ifTrue: [ aStream crtab ]]] ifFalse: [ aStream nextPutAll: '' ]. aStream cr.
</methods> <methods> Net.CookieField class <category>instance creation</category>
new ^self newWithVersion: self defaultVersion
newNetscape ^super new initialize
newRfc ^self new
newWithVersion: aNumber ^super new initialize; version: aNumber; yourself
</methods> <methods> Net.CookieField class <category>defaults</category>
defaultSeparators ^#($; $; $; )
</methods> <methods> Net.CookieField class <category>parsing</category>
fieldNames ^#('cookie' )
</methods> <methods> Net.HttpSocketAccessor <category>private</category>
primReadInto: buffer startingAt: index for: count "buffer is a byte-object, the place where IO is performed. index is a SmallInteger, the starting-point in the buffer. count is a SmallInteger, the number of bytes to be read." "Returns a SmallInteger, which is the count of the bytes read." "WouldBlock is a potential error condition." time := Time millisecondClockValue. ^super primReadInto: buffer startingAt: index for: count
privateReadInto: buffer startingAt: index for: count "buffer is a byte-object, the place where IO is performed. index is a SmallInteger, the starting-point in the buffer. count is a SmallInteger, the number of bytes to be read." "Returns a SmallInteger, which is the count of the bytes read." "WouldBlock is a potential error condition." <primitive: 679> | newTime | (self class restartableError: errorCode) ifTrue: [self readWaitWithTimeoutMs: self timeout. newTime := Time millisecondClockValue. newTime - time > self timeout ifTrue: [ ^HttpTimeout raise]. ^OSErrorHolder needRetrySignal raise]. ^self reportErrorProceeding
</methods> <methods> Net.HttpSocketAccessor <category>accessing</category>
timeout timeout == nil ifTrue: [timeout := 6000]. ^timeout
timeout: numberOfMilliseconds timeout := numberOfMilliseconds
</methods> <methods> Net.HttpSocketAccessor <category>defaults</category>
connectionClass "Answer a default connection class for the receiver." ^ExternalConnection
</methods> <methods> Net.HttpConnection <category>testing</category>
accepts: url ^url protocol = 'http'
</methods> <methods> Net.HttpConnection <category>private</category>
createSocketTimeout: aNumber | s | s := self class defaultSocketAccessor family: (SocketAddress domainCodeFromName: #afInet) type: SocketAccessor sockStream. s timeout: aNumber. ^s
</methods> <methods> Net.HttpConnection class <category>default values</category>
defaultPortNumber ^SocketAccessor IPPORT_HTTP
defaultSocketAccessor ^HttpSocketAccessor
</methods> <methods> Net.HttpMovedError <category>accessing</category>
location ^self parameter location
</methods> <methods> Net.UseChunkingForSingleChunk <category>constants</category>
defaultResumeValue ^false
</methods> <methods> Net.DigestAuthenticationValue <category>accessing</category>
algorithm ^self paramAt: 'algorithm'
algorithm: aString ^self paramAt: 'algorithm' put: aString
authParam "This directive allows for future extensions." ^self paramAt: 'auth-param'
authParam: aString ^self paramAt: 'auth-param' put: aString
cnonce "This MUST be specified if a qop directive is sent " ^self paramAt: 'cnonce'
cnonce: aString ^self paramAt: 'cnonce' put: aString
digestUri "The URI from Request-URI of the Request-Line; duplicated here because proxies are allowed to change the Request-Line in transit." ^self paramAt: 'digest-uri'
digestUri: aString ^self paramAt: 'digest-uri' put: aString
nc ^self paramAt: 'nc'
nc: aNumber ^self paramAt: 'nc' put: aNumber
nonce ^self paramAt: 'nonce'
nonce: aString self paramAt: 'nonce' put: aString
opaque "A string of data, specified by the server, which should be returned by the client unchanged in the Authorization header of subsequent requests with URIs in the same protection space. It is recommended that this string be base64 or hexadecimal data." ^self paramAt: 'opaque'
opaque: aString ^self paramAt: 'opaque' put: aString
qop "Indicates what 'quality of protection' the client has applied to the message" ^self paramAt: 'qop'
qop: aCollection " qop-options = qop = <''> 1#qop-value <''> qop-value = auth | auth-int | token " self paramAt: 'qop' put: aCollection
realm ^self paramAt: 'realm'
realm: aString ^self paramAt: 'realm' put: aString
response " A string of 32 hex digits, which proves that the user knows a password" ^self paramAt: 'response'
response: aString ^self paramAt: 'response' put: aString
scheme ^self value
stale "A flag, indicating that the previous request from the client was rejected because the nonce value was stale. If stale is TRUE (case-insensitive), the client may wish to simply retry the request with a new encrypted response, without reprompting the user for a new username and password. " ^self paramAt: 'stale'
stale: aBoolean ^self paramAt: 'stale' put: aBoolean
uri ^self paramAt: 'uri'
uri: aString ^self paramAt: 'uri' put: aString
username "The user's name in the specified realm" ^self paramAt: 'username'
username: aString ^self paramAt: 'username' put: aString
</methods> <methods> Net.DigestAuthenticationValue <category>accessing auth-info</category>
nextNonce ^self paramAt: 'nextnonce'
nextNonce: aString self paramAt: 'nextnonce' put: aString
responseAuth ^self paramAt: 'rspauth'
responseAuth: aString ^self paramAt: 'rspauth' put: aString
</methods> <methods> Net.DigestAuthenticationValue <category>printing</category>
printNonceCount: aNumber on: aStream aNumber printOn: aStream paddedWith: $0 to: 8 base: 10.
printNonceCountOn: aStream | number | (number := self nc) ifNotNil: [ self printNonceCount: number on: aStream]
printParameter: name value: anObject on: aStream anObject isNil ifTrue: [^nil]. self class scannerType print: $= on: aStream. name = 'qop' ifTrue: [^self printQop: anObject on: aStream]. name = 'nc' ifTrue: [^self printNonceCount: anObject on: aStream]. name = 'stale' ifTrue: [ ^self printQuotedValue: anObject printString on: aStream ]. self printQuotedValue: anObject on: aStream.
printParametersSeparatorOn: aStream aStream nextPut: self parametersSeparator; crtab
printQop: anObject on: aStream anObject isString ifTrue: [aStream nextPutAll: anObject] ifFalse: [ aStream nextPut: $". anObject do: [ :each | aStream nextPutAll: each] separatedBy: [aStream nextPut: $,]. aStream nextPut: $".].
printQuotedValue: anObject on: aStream aStream nextPut: $"; nextPutAll: anObject; nextPut: $"
</methods> <methods> Net.DigestAuthenticationValue <category>testing</category>
isBasic ^false
isDigest ^true
isNTLM ^false
isNTLMType2 ^false
isStaleTrue ^self stale = true
</methods> <methods> Net.DigestAuthenticationValue <category>parsing</category>
finishParse | coll sc val | coll := OrderedCollection new. (val := self qop) ifNotNil: [sc := self scannerOn: val readStream. sc tokenizeList: [ coll add: sc nextToken ] separatedBy: [sc token == $, or: [sc token == Character space ]]. self qop: coll. ]. (val := self stale) ifNotNil: [self stale: (Boolean readFrom: val readStream) ]. (val := self nc) ifNotNil: [self nc: (Number readFrom: val readStream) ].
parse: scanner scanner atEnd ifTrue: [ ^self]. scanner hereChar ~~ self valueSeparator ifTrue: [ scanner stepBack. ^self ]. self parseParameters: scanner. self finishParse.
</methods> <methods> Net.DigestAuthenticationValue <category>initialize-release</category>
initialize value := 'Digest'
</methods> <methods> Net.DigestAuthenticationValue <category>composing</category>
writeParameter: assoc on: aStream encoding: aString self printParameter: assoc on: aStream
</methods> <methods> Net.HttpRequestLine <category>visiting</category>
acceptVisit: aVisitor with: argument ^aVisitor acceptRequestLine: self with: argument
</methods> <methods> Net.HttpRequestLine <category>accessing</category>
entityType ^HttpRequest
extendedMethod ^self prefix notNil ifTrue: [ self prefix, self method] ifFalse: [self method]
headerOnly ^self method asSymbol == #HEAD
host ^self url ~~ nil ifTrue: [ self url host ] ifFalse: [ nil ]
hostAndPort ^self url ~~ nil ifTrue: [self url hostAndPort ] ifFalse: [ nil ]
method ^method
method: aString method := aString
parent ^nil
path ^path
pathString ^url isNil ifTrue: [ path] ifFalse: [self useProxy ifTrue: [self url asString] ifFalse: [self url pathString]].
port ^self url ~~ nil ifTrue: [ self url port ] ifFalse: [ nil ]
prefix ^prefix
prefix: aString prefix := aString
protocol ^self url ~~ nil ifTrue: [ self url protocol asLowercase ] ifFalse: [self version ~~ nil ifTrue: [ (self version copyFrom: 1 to: (self version indexOf: $/ ) - 1) asLowercase ] ifFalse: ['http']]
url ^url
url: anURL url := anURL asURI
useProxy useProxy ifNil: [ useProxy := Settings httpUseProxy ]. ^useProxy
useProxy: aBoolean useProxy := aBoolean
version (version isNil or: [ version isEmpty]) ifTrue: [ version := self class defaultVersion]. ^version
version: aString version := aString
</methods> <methods> Net.HttpRequestLine <category>composing</category>
writeOn: aStream self printOn: aStream
</methods> <methods> Net.HttpRequestLine <category>testing</category>
hasAbsoluteURI ^self url ~~ nil
isHttp10 ^'*1.0*' match: self version
isValid ^((#('POST' 'PUT' 'OPTIONS' 'GET' 'HEAD' 'DELETE' 'TRACE') includes: self method) and: [ 'HTTP*' match: self version])
</methods> <methods> Net.HttpRequestLine <category>parsing</category>
readFrom: stream | scanner index strUrl | scanner := MimeScanner on: stream. method := scanner nextToken. (index := method indexOf: $-) > 0 ifTrue: [prefix := method copyFrom: 1 to: index. method := method copyFrom: index + 1 to: method size]. scanner skipWhiteSpace. strUrl := scanner upTo: Character space. ('http*' match: strUrl) ifTrue: [url := strUrl asURI ] ifFalse: [path := strUrl]. version := scanner scanText.
</methods> <methods> Net.HttpRequestLine <category>printing</category>
printOn: aStream aStream nextPutAll: self extendedMethod; space; nextPutAll: self pathString; space; nextPutAll: self version.
</methods> <methods> Net.HttpRequestLine class <category>instance creation</category>
method: aMethodString url: requestURI ^self new method: aMethodString; url: requestURI; yourself
readFrom: stream ^self new readFrom: stream
</methods> <methods> Net.HttpRequestLine class <category>defaults</category>
defaultVersion ^'HTTP/1.1'
</methods> <methods> Net.ChunkedWriteStream <category>accessing</category>
bufferNumber ^bufferNumber
chunkSize: aNumber self writeLimit: aNumber
flush "Write any unwritten information "
nextPut: anObject "Put the argument, anObject, at the next position in the receiver. Answer anObject." position = self writeLimit ifTrue: [ self writeChunk ]. buffer ifNil: [self initializeWriteBuffer ]. position := position + 1. buffer at: position put: anObject asInteger. ^anObject
useChunks ^useChunks ifNil: [ true]
useChunks: aBoolean useChunks := aBoolean
writeLimit ^writeLimit ifNil: [writeLimit := self class defaultWriteLimit ]
writeLimit: aNumber writeLimit := aNumber
</methods> <methods> Net.ChunkedWriteStream <category>status</category>
close self finish. stream close.
finish "Write any unwritten information and last chunk last-chunk = 1*('0') [ chunk-extension ] CRLF chunk-extension= *( ';' chunk-ext-name [ '=' chunk-ext-val ] ) chunk-ext-name = token chunk-ext-val = token | quoted-string chunk-data = chunk-size(OCTET) trailer = *(entity-header CRLF) " buffer ifNotNil: [bufferNumber == 0 ifTrue: [ self useChunks: ( UseChunkingForSingleChunk raiseRequestWith: position). bufferNumber := 1.]. self useChunks ifTrue: [self writeChunk. self writeLastChunk] ifFalse: [ self writeBuffer ]]. stream finish.
</methods> <methods> Net.ChunkedWriteStream <category>private</category>
beginWriteChunk self useChunks ifTrue: [| s | s := EncodedStream on: (ByteArray new: 100) writeStream encodedBy: (StreamEncoder new: #ascii). position printOn: s base: 16. stream nextPutAll: s encodedContents; nextPutAll: self lineEnd].
endWriteChunk self useChunks ifTrue: [stream nextPutAll: self lineEnd].
initializeWriteBuffer buffer := self contentsSpecies new: self writeLimit. position := 0
signalReadyToWrite bufferNumber == 0 ifTrue: [ self useChunks: ( ReadyToWriteFirstChunk raiseRequestWith: stream) ]
writeBuffer buffer ifNotNil: [stream nextPutAll: (buffer copyFrom: 1 to: position). bufferNumber := bufferNumber + 1. buffer := nil. ]
writeChunk buffer ifNotNil: [stream binary. self signalReadyToWrite. self beginWriteChunk. self writeBuffer. self endWriteChunk. ]
writeLastChunk self useChunks ifTrue: [stream nextPut: $0 asInteger. stream nextPutAll: self lineEnd. stream nextPutAll: self lineEnd ].
</methods> <methods> Net.ChunkedWriteStream <category>initialize-release</category>
initializeOn: aStream super initializeOn: aStream. bufferNumber := 0
</methods> <methods> Net.ChunkedWriteStream <category>testing</category>
isReadable ^false
isWritable "Answer whether the stream implements #nextPut:." ^true
</methods> <methods> Net.ChunkedWriteStream class <category>defaults</category>
defaultWriteLimit ^defaultWriteLimit ifNil: [defaultWriteLimit := self defaultWriteLimitValue]
defaultWriteLimit: aNumber defaultWriteLimit := aNumber
defaultWriteLimitValue ^4096
</methods> <methods> Net.HttpBuildHandler <category>defaults</category>
defaultRootEntityType ^HttpEntity
parserClass ^HttpParser
</methods> <methods> Net.HttpBuildHandler <category>options</category>
decodeContents ^decodeContents ifNil: [ self class decodeContents ]
decodeContents: aBoolean decodeContents := aBoolean
decompressContents ^decompressContents ifNil: [ self class decompressContents ]
decompressContents: aBoolean decompressContents := aBoolean
</methods> <methods> Net.HttpBuildHandler <category>private prepare streams</category>
prepareStream: aStream forMessageBody: anEntity stream := aStream. anEntity isChunked ifTrue: [ stream := ChunkedReadStream on: stream ]. stream := BodyStream on: stream length: anEntity contentLength. anEntity isTransferEncodingGZip ifTrue: [ stream := OS.ZLib.GZipReadStream on: stream ]. ^stream
prepareStream: aStream forSimpleBody: aBody ^(self shouldBeDecompressed: aBody parent) ifTrue: [ OS.ZLib.GZipReadStream on: aStream ] ifFalse: [aStream]
setAttachmentSource: aBody to: aStream aBody byteSource: aStream
</methods> <methods> Net.HttpBuildHandler <category>private</category>
decodeBody: aBody | ce | (aBody isMultipart or: [ aBody isBinary or: [aBody byteSource isNil ]]) ifTrue: [^aBody]. (((ce := aBody parent contentEncoding) notNil and: [ce notEmpty]) or: [self decodeContents not]) ifFalse: [self setBodySource: aBody]
handleStartBody: aBody exception: exception (HttpTimeout handles: exception) ifTrue: [exception parameter: aBody parent. exception pass] ifFalse: [ super handleStartBody: aBody exception: exception ]
</methods> <methods> Net.HttpBuildHandler <category>testing</category>
shouldBeDecompressed: anEntity ^(self decompressContents and: [anEntity isContentEncodingGZip ])
</methods> <methods> Net.HttpBuildHandler <category>action callbacks</category>
endBody: aBody (self shouldBeDecompressed: aBody parent) ifTrue: [aBody parent removeFieldAt: 'content-encoding']. aBody parent isContentEncodingGZip ifFalse: [ self decodeBody: aBody]. ^super endBody: aBody
endMessageBody: aBody | message | message := aBody parent. (message isChunked or: [message isTransferEncodingGZip]) ifTrue: [ message removeFieldAt: 'transfer-encoding']. ^message
shouldStartMessageBody: aMessageBody | message | message := aMessageBody parent. message isMimeEntity ifTrue: [^true]. (self headerOnly or: [message headerOnly]) ifTrue: [ ^false ]. ^message contentLength ifNil: [ message isChunked or: [ message isConnectionTransient ] ] ifNotNil: [ :length | length > 0 ]
startMessage: aLineObject initialEntity isNil ifTrue: [ initialEntity := aLineObject entityType new]. initialEntity messageLine: aLineObject. ^initialEntity
</methods> <methods> Net.HttpBuildHandler class <category>defaults</category>
decodeContents ^decodeContents isNil ifTrue: [decodeContents := self decodeContentsValue] ifFalse: [decodeContents]
decodeContents: aBoolean decodeContents := aBoolean
decompressContents ^decompressContents isNil ifTrue: [decompressContents := self defaultDecompressContents ] ifFalse: [decompressContents]
decompressContents: aBoolean decompressContents := aBoolean
</methods> <methods> Net.HttpBuildHandler class <category>default values</category>
decodeContentsValue ^true
defaultAttachmentDirectoryValue ^'http-temp-files'
defaultDecompressContents ^true
saveAttachmentsAsFilesValue ^true
</methods> <methods> Net.HttpTimeout <category>private</category>
defaultMessageText ^(#TimeoutConnectionNotResponding << #net >> 'Timeout Connection is not responding') asString
</methods> <methods> Net.RegistryLimitationExc <category>printing</category>
defaultMessageText ^'Cookie implementation limits'
</methods> <methods> Net.HttpURL <category>stream -- guarded</category>
envelopeReadStreamDo: aBlock ^self safelyExecuteBlock: [self clientDo: [ :client | client readStreamCmd: 'GET' url: self do: [ :connection | aBlock value: connection ]]]
envelopeWriteStreamDo: aBlock ^self shouldNotImplement
readByteStreamDo: aBlock "Returns not decoded byte array stream and the response header fields " | message dictionary | self safelyExecuteBlock: [message := self clientDo: [ :client | client decodeContents: false; get: self ]]. self checkMultipart: message. dictionary := Dictionary new. message fields do: [:fld | dictionary at: fld name put: fld ]. ^aBlock value: message byteSource reset value: dictionary
readStreamDo: aBlock "Returns the response contents stream and the response header fields." | message dictionary | self safelyExecuteBlock: [message := self get ]. self checkMultipart: message. dictionary := Dictionary new. message fields do: [:fld | dictionary at: fld name put: fld ]. ^aBlock value: message contents readStream value: dictionary
writeStreamDo: aBlock ^self shouldNotImplement
</methods> <methods> Net.HttpURL <category>stream -- unguarded</category>
binaryReadStream "Returns stream on ByteArray" | message | self safelyExecuteBlock: [message := self get ]. self checkMultipart: message. ^message contents asByteArray readStream
binaryWriteStream ^self shouldNotImplement
envelopeReadStream ^self safelyExecuteBlock: [self client readStreamCmd: 'GET' url: self]
envelopeWriteStream ^self shouldNotImplement
readStream "Returns stream on ByteString" | message | self safelyExecuteBlock: [message := self get ]. self checkMultipart: message. ^message contents readStream.
writeStream ^self shouldNotImplement
</methods> <methods> Net.HttpURL <category>private</category>
checkMultipart: aHttpEntity aHttpEntity isMultipart ifTrue: [self error: (#MultipartBodiesAreNotYetSupported << #net >> 'Multipart bodies are not yet supported')].
client | client | client := HttpClient new. self user ifNotNil: [ client user: self user ]. client decodeContents: self decodeContents; decompressContents: self decompressContents. ^client
newClient "Obsolete" ^self client
protocolSignals ^HttpException
safelyExecuteBlock: aBlock ^aBlock on: HttpUnauthorizedError do: [ :ex | self user notNil ifTrue: [ ex pass] ifFalse: [Settings httpUser notNil ifTrue: [ self user: Settings httpUser. ex retry ] ifFalse: [ ex pass]]]
</methods> <methods> Net.HttpURL <category>accessing</category>
clientDo: aBlock | client | client := self client. ^[ aBlock value: client ] ensure: [ client ifNotNil: [ client close]]
decodeContents ^decodeContents ifNil: [decodeContents := HttpBuildHandler decodeContents]
decodeContents: aBoolean decodeContents := aBoolean
decompressContents ^decompressContents ifNil: [decompressContents := HttpBuildHandler decompressContents]
decompressContents: aBoolean decompressContents := aBoolean
hostAddress ^self socketAddress hostAddress
hostAndPort ^port = self defaultPortNumber ifTrue: [host] ifFalse: [host, ':', port printString]
pathString | stream str | stream := (String new: 32) writeStream. path do: [:s | stream nextPutAll: '/', s]. str := stream contents. str isEmpty ifTrue: [str := '/']. query notNil ifTrue: [str := str, '?', query]. ^str
resource | message data | self safelyExecuteBlock: [message := self get ]. self checkMultipart: message. data := message body source notNil ifTrue: [message charset asSymbol = #'utf-8' ifTrue: [message body source] ifFalse: [message body source encoder: (StreamEncoder new: #UTF_8)]] ifFalse: [ (EncodedStream on: message body byteSource encodedBy: (StreamEncoder new: #UTF_8)) lineEndConvention: LineEndTransparent]. data reset. ^XML.InputSource uri: self encoding: nil stream: data
socketAddress ^IPSocketAddress hostName: self host port: self port
user ^user
user: aNetUser user := aNetUser
username: nameString password: passString user := HttpUser username: nameString password: passString
</methods> <methods> Net.HttpURL <category>commands</category>
get ^self clientDo: [ :client | client get: self ]
</methods> <methods> Net.HttpURL class <category>accessing</category>
protocol ^'http'
</methods> <methods> Net.HttpURL class <category>defaults</category>
defaultPortNumber ^SocketAccessor IPPORT_HTTP
</methods> <methods> Net.AcceptField <category>accessing</category>
levelAt: index ^(self mediaRangeAt: index) paramAt: 'level'
mediaRangeAt: index ^self value at: index
mediaTypeAt: index ^(self mediaRangeAt: index) value
</methods> <methods> Net.AcceptField <category>adding media range</category>
addMedia: vString self addMedia: vString qValue: nil
addMedia: vString level: lString self addMedia: vString qValue: nil level: lString
addMedia: vString qValue: qString self addMedia: vString qValue: qString level: nil
addMedia: vString qValue: qString level: lString | valWithParams | valWithParams := self addValue: vString qValue: qString. lString notNil ifTrue: [ valWithParams paramAt: 'level' put: lString].
</methods> <methods> Net.AcceptField class <category>parsing</category>
fieldNames ^#('accept')
</methods> <methods> Net.AcceptField class <category>instant creation</category>
media: vString ^self media: vString qValue: nil level: nil
media: mString level: lString ^self media: mString qValue: nil level: lString
media: vString qValue: qString ^self media: vString qValue: qString level: nil
media: mString qValue: qString level: lString " Answer an instance of this field representing media range" ^(self name: 'accept') addMedia: mString qValue: qString level: lString; yourself
</methods> <methods> Net.HttpEntityError <category>printing</category>
description ^self messageText
</methods> <methods> OS.ZLib.DeflateStream <category>status</category>
finish "Write any unwritten information." self finishBuffer. self finishOutput. destinationStream finish
</methods> <methods> Net.MimeOutputHandler <category>action callbacks</category>
startRequestLine: aRequestLine with: aHttpEntity aHttpEntity isExtended ifTrue: [aRequestLine prefix: 'm-'] ifFalse: [aRequestLine prefix: nil]. self printLine: aRequestLine printString. aHttpEntity hasHostField ifFalse: [aHttpEntity host: aRequestLine hostAndPort]
startResponseStatusLine: aResponseStatusLine with: aHttpEntity self printLine: aResponseStatusLine printString.
</methods> <methods> Core.TwoByteString <category>private-auth</category>
md5Hash ^self
</methods> <methods> Core.String <category>private-auth</category>
md5Hash "answer a hexadecimal encoded hash" | stream | stream := WriteStream on: String new. self asByteArray md5Value printOn: stream base: 16. ^stream contents
</methods> <initialize> Net.HttpProtocolInterpreter </initialize> <initialize> Net.HttpClient </initialize> "Imported Classes:" self error: 'Attempting to file-in parcel imports. Choose terminate or close' <class> <name>Object</name> <environment>Core</environment> <super></super> <private>false</private> none <imports></imports> <category>Kernel-Objects</category> <attributes> <package>Kernel-Objects</package> </attributes> </class> <class> <name>SocketAccessor</name> <environment>OS</environment> <super>OS.BlockableIOAccessor</super> <private>false</private> none concreteClass <imports></imports> <category>OS-Sockets</category> <attributes> <package>OS-Sockets</package> </attributes> </class> <class> <name>MessageStream</name> <environment>Net</environment> <super>Core.Stream</super> <private>true</private> none stream position readLimit <imports></imports> <category>HTTP</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>MimeOutputHandler</name> <environment>Net</environment> <super>Net.MimeDispatcherHandler</super> <private>false</private> none streams fieldStream <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>MimePrintHandler</name> <environment>Net</environment> <super>Net.MimeOutputHandler</super> <private>false</private> none indentation indentLines <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>NetUser</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none username password fullName account savePassword mailAddress <imports></imports> <category>Net-Clients</category> <attributes> <package>NetClientBase</package> </attributes> </class> <class> <name>MimeWriteHandler</name> <environment>Net</environment> <super>Net.MimeOutputHandler</super> <private>false</private> none preferFieldSource originalStream binaryMode applyTransferEncoding applyTransferEncoding <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>NetNotification</name> <environment>Net</environment> <super>Core.Notification</super> <private>false</private> none <imports></imports> <category>Net-Clients</category> <attributes> <package>NetClientBase</package> </attributes> </class> <class> <name>HeaderFieldValue</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none separators value <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>ValueWithParams</name> <environment>Net</environment> <super>Net.HeaderFieldValue</super> <private>false</private> none params defaultParameterValueEncoding <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>MimeDispatcher</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none handler <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>String</name> <environment>Core</environment> <super>Core.CharacterArray</super> <private>false</private> none <imports></imports> <category>Collections-Text</category> <attributes> <package>Collections-Text</package> </attributes> </class> <class> <name>TwoByteString</name> <environment>Core</environment> <super>Core.String</super> <private>false</private> bytes <imports></imports> <category>Collections-String Support</category> <attributes> <package>Collections-String Support</package> </attributes> </class> <class> <name>NetProtocolInterpreter</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none connection defaultNetConnection <imports></imports> <category>Net-Clients</category> <attributes> <package>NetClientBase</package> </attributes> </class> <class> <name>DeflateStream</name> <environment>OS.ZLib</environment> <super>Core.WriteStream</super> <private>false</private> none outputBuffer interface destinationStream compressionLevel <imports></imports> <category>Compression-ZLib</category> <attributes> <package>Compression-ZLib</package> </attributes> </class> <class> <name>URLwithAuthority</name> <environment>OS</environment> <super>OS.URLwithPath</super> <private>false</private> none host port <imports></imports> <category>Net-Resources</category> <attributes> <package>URISupport</package> </attributes> </class> <class> <name>MimeEntity</name> <environment>Net</environment> <super>Net.MessageElement</super> <private>false</private> none header headerCharset builderClass printerClass writerClass <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>StructuredHeaderField</name> <environment>Net</environment> <super>Net.HeaderField</super> <private>false</private> none comment <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>ValueWithParametersField</name> <environment>Net</environment> <super>Net.StructuredHeaderField</super> <private>false</private> none separators <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>MimeParser</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none handler <imports> private OS.IOConstants.* </imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>CollectionField</name> <environment>Net</environment> <super>Net.StructuredHeaderField</super> <private>false</private> none separator <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>NetConnection</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none stream encoding <imports> private OS.IOConstants.* </imports> <category>Net-Clients</category> <attributes> <package>NetClientBase</package> </attributes> </class> <class> <name>MimeParserHandler</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none fieldFactory messageHeaderClass scannerType stream lineEndConvention initialEntity saveAttachmentsAsFiles parser headerOnly binaryMode acceptNonAsciiCharacters saveAttachmentsAsFiles defaultAttachmentDirectory <imports></imports> <category>Net-MIME-Support</category> <attributes> <package>MIME</package> </attributes> </class> <class> <name>NetClient</name> <environment>Net</environment> <super>Core.Object</super> <private>false</private> none user hostName portNumber clientPI retries timeout delaySeconds state defaultProtocolInterpreterClass <imports></imports> <category>Net-Clients</category> <attributes> <package>NetClientBase</package> </attributes> </class> <class> <name>NetError</name> <environment>Net</environment> <super>Core.Error</super> <private>false</private> none <imports></imports> <category>Net-Clients</category> <attributes> <package>NetClientBase</package> </attributes> </class>