From b7c59555e9740faa853fbed7e65c75bf647a3a54 Mon Sep 17 00:00:00 2001 From: Luc Fabresse Date: Tue, 23 Dec 2014 17:03:20 +0100 Subject: [PATCH] pass on Zinc-HTTP (first part) --- PossibleOutlineAndCurrentStatus.txt | 3 +- Zinc-HTTP/Zinc-HTTP.pillar | 109 ++++++++++++++-------------- pillar.conf | 8 +- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/PossibleOutlineAndCurrentStatus.txt b/PossibleOutlineAndCurrentStatus.txt index 9f7175a..33d66e4 100644 --- a/PossibleOutlineAndCurrentStatus.txt +++ b/PossibleOutlineAndCurrentStatus.txt @@ -56,11 +56,12 @@ BabyMock/BabyMock.pier Zinc/Zinc.pier >> may be old and we should read the Zinc* chapter >> Stef should re read it. + >> Luc should be removed because Zinc-HTTP is a fork of this one [22 Dec 2014] - Zinc-HTTP >> Stef should re read it. + >> Luc is doing a pass and test snippets on Pharo #40420 [22 Dec 2014] Zinc-REST >> Stef should read it and ask crhistophe for feedback. diff --git a/Zinc-HTTP/Zinc-HTTP.pillar b/Zinc-HTTP/Zinc-HTTP.pillar index f543fb5..b10af7d 100644 --- a/Zinc-HTTP/Zinc-HTTP.pillar +++ b/Zinc-HTTP/Zinc-HTTP.pillar @@ -1,12 +1,12 @@ -! HTTP +!HTTP -HTTP is arguably the most important application level network protocol for what we consider to be the internet. It is the protocol that allows web browsers and web servers to communicate. It is also becoming the most popular protocol for implementing web services. +HTTP is arguably the most important application level network protocol for what we consider to be the Internet. It is the protocol that allows web browsers and web servers to communicate. It is also becoming the most popular protocol for implementing web services. -Naturally, Pharo has out of the box support for HTTP. Zinc is a robust, fast and elegant HTTP client and server library written and maintained by Sven van Caekenberghe. +Naturally, Pharo has out of the box support for HTTP. Zinc is a robust, fast and elegant HTTP client and server library written and maintained by Sven van Caekenberghe. -- todo: add a conclusion + @@TODO: add a conclusion@@ -!! An introduction to HTTP +!!An introduction to HTTP HTTP, short for Hypertext Transfer Protocol, functions as a request-response protocol in the client-server computing model. As an application level protocol it is layered on top of a reliable transport such as a TCP socket stream. The most important standard specification document describing HTTP version 1.1 is *RFC 2616>http://tools.ietf.org/html/rfc2616*. As usual another good starting point is the Wikipedia article on *HTTP>http://en.wikipedia.org/wiki/Http*. @@ -21,7 +21,7 @@ To specify which resource you want, a URL (Uniform Resource Locator) is used. We The reliable transport connection between an HTTP client and server is used bidirectionally: both to send the request as well as to receive the response. It can be used for just one request/response cycle, as was the case for HTTP version 1.0, or it can be reused for multiple request/response cycles, as is the default for HTTP version 1.1. -!! Zinc +!!Zinc Zinc, the short form for *Zinc HTTP>http://zn.stfx.eu/* Components, is an open-source Smalltalk framework to deal with HTTP. It models most concepts of HTTP and its related standards and offers both client and server functionality. One of its key goals is to offer understandability (Smalltalk's design principle number one). Anyone with a basic understanding of Smalltalk and the HTTP principles should be able to understand what is going on and learn, by looking at the implementation. Zinc, or Zn, after its namespace prefix, is an integral part of Pharo Smalltalk since version 1.3. It has been ported to other Smalltalk implementations such as Gemstone. @@ -33,7 +33,7 @@ The reference Zn implementation lives in several places: Installation or updating instructions can be found there. -!! Doing a simple request +!!Doing a simple request The key object to programmatically execute HTTP requests is called ==ZnClient==. You instantiate it, use its rich API to configure and execute an HTTP request and access the response. ==ZnClient== is a stateful object that acts as a builder. Let's get started with the simplest possible usage. @@ -41,7 +41,7 @@ The key object to programmatically execute HTTP requests is called ==ZnClient==. ZnClient new get: 'http://zn.stfx.eu/zn/small.html'. ]]] -Select the above expression and inspect or print it. If all goes well, you'll get a ==String== back containing a very small HTML document. The ==get:== method belongs to the convenience API. Let's be a bit more explicit about what happened. +Select the above expression and inspect or print it. If all goes well, you'll get a ==String== back containing a very small HTML document. The ==get:== method belongs to the convenience API. Let's use a more general API to be a bit more explicit about what happened. [[[ ZnClient new @@ -50,22 +50,22 @@ ZnClient new response. ]]] -Here we explicitly set the url using ==url:==, execute an HTTP GET using ==get== and ask for the response object using ==response==. The above returns a ==ZnResponse== object. Of course you can inspect it. It consists of 3 elements: +Here we explicitly set the url of the resource to access using ==url:==, then we execute an HTTP GET using ==get== and we finally ask for the response object using ==response==. The above returns a ==ZnResponse== object. Of course you can inspect it. It consists of 3 elements: # a ==ZnStatusLine== object, # a ==ZnHeaders== object and -# an optional ==ZnEntity== object +# an optional ==ZnEntity== object. The status line says HTTP/1.1 200 OK, which means the request was successful. This can be tested by sending ==isSuccess== to either the response object or the client itself. The headers contain meta data related to the response, including: -- the content-type (a mime-type), accessed with the message ==contentType== -- the content-length (a byte count), accessed with the message ==contentLength== +- the content-type (a mime-type), accessible with the message ==contentType== +- the content-length (a byte count), accessible with the message ==contentLength== - the date the response was generated - the server that generated the response The entity is the actual resource: the bytes that should be interpreted in the context of the content-type mime-type. Zn automatically converts non-binary mime-types into ==String==s using the correct encoding. In our example, the entity is an instance of ==ZnStringEntity==, a concrete subclass of ==ZnEntity==. -Like any Smalltalk object, you can inspect or explore the ==ZnResponse== object. You might be wondering how this response was actually transferred over the network. That is easy with Zinc, as the key HTTP objects all implement ==writeOn:== for this purpose. @@so?? You can simply ask a response to write itself onto the Transcript. Still I do not understand how this is answering the question? We should address that point@@ +Like any Smalltalk object, you can inspect or explore the ==ZnResponse== object. You might be wondering how this response was actually transferred over the network. That is easy with Zinc, as the key HTTP objects all implement ==writeOn:== that displays the raw format of the response i.e. what has been transmitted through the network. [[[ | response | @@ -77,7 +77,7 @@ response writeOn: Transcript. Transcript flush. ]]] -If you have the Transcript open, you should see something like the following: +If you have the Transcript open, you should something like the following: [[[language=http HTTP/1.1 200 OK @@ -96,7 +96,7 @@ Content-Type: text/html;charset=utf-8 The first CRLF terminated line is the status line. Next are the headers, each on a line with a key and a value. An empty line ends the headers. Finally, the entity bytes follows, either up to the content length or up to the end of the stream. -You might wonder what the request looked like as it went over the line ? You can find out using the same technique. +You might wonder what the request looked like when it went over the network? You can find it out using the same technique. [[[ | request | @@ -115,6 +115,7 @@ GET /zn/small.html HTTP/1.1 Accept: */* User-Agent: Zinc HTTP Components 1.0 Host: zn.stfx.eu + ]]] A ==ZnRequest== object consists of 3 elements: @@ -162,7 +163,7 @@ Content-Type: text/html;charset=utf-8 In a later subsection about server logging, which uses the same mechanism, you will learn how to interpret and customize logging. -!! HTTP Success ? +!!HTTP Success ? A simple view of HTTP is: you request a resource and get a response back containing the resource. But even if the mechanics of HTTP did work, and even that is not guaranteed (see the next section), the response could not be what you expected. @@ -185,7 +186,7 @@ client isSuccess ifFalse: [ self inform: 'Something went wrong' ] ]]] -To make it easier to write better HTTP client code, ==ZnClient== offers some useful API. You can ask the client to consider non-successful HTTP responses as errors with the ==enforceHTTPSuccess== option. The client will then automatically throw a ==ZnHTTPUnsuccesful== exception. This is generally useful when upstream code handles errors. @@What is an upstream code???@@. +To make it easier to write better HTTP client code, ==ZnClient== offers some useful API. You can ask the client to consider non-successful HTTP responses as errors with the ==enforceHTTPSuccess== option. The client will then automatically throw a ==ZnHTTPUnsuccesful== exception. This is generally useful when upstream code handles errors. @@TODO: What is an upstream code???@@. To install a local failure handler, there is the ==ifFail:== option. This will invoke a block, optionally passing an exception, whenever something goes wrong. Together, this allows the above code to be rewritten as follows. @@ -199,7 +200,7 @@ ZnClient new Maybe it doesn't look like a big difference, but combined with some other options and features of ==ZnClient== that we'll see later on, code does become more elegant and more reliable at the same time. -!! Dealing with networking reality +!!Dealing with networking reality As a network protocol, HTTP is much more complicated than an ordinary message send. The famous *Fallacies of Distributed Computing>http://en.wikipedia.org/wiki/Fallacies_of_Distributed_Computing* eloquently list the issues involved: @@ -256,7 +257,7 @@ In the above example, the request will be tried up to 3 times, with a 2 second d !! Building URL's -Zn uses ==ZnUrl== objects to deal with URLs. ==ZnClient== also contains API to build URLs. Let us revisit our initial example, using explicit URL construction with the ==ZnClient== API. +Zn uses ==ZnUrl== objects to deal with URLs. ==ZnClient== also contains an API to build URLs. Let us revisit our initial example, using explicit URL construction with the ==ZnClient== API. [[[ ZnClient new @@ -269,7 +270,7 @@ ZnClient new Instead of giving a string argument to be parsed into a ==ZnUrl==, we now provide the necessary elements to construct the URL manually, by sending messages to our ==ZnClient== object. With ==http== we set what is called the scheme. Then we set the hostname. Since we don't specify a port, the default port for HTTP will be used, port 80. Next we add path elements, extending the path one by one. -A URL can also contain query parameters. Let's do a Google search. +A URL can also contain query parameters. Let's do a Google search as an example: [[[ ZnClient new @@ -292,19 +293,19 @@ ZnUrl new yourself. ]]] -The printable representation of the URL is the following. Now you can inspect the following expressions. +If you print the above expression, it gives you the printable representation of the URL. % @@todo add a screen shot@@ = http://www.google.com/search?q=Pharo%20Smalltalk -This can easily be parsed again into a ==ZnUrl== object +This string version can easily be parsed again into a ==ZnUrl== object = 'http://www.google.com/search?q=Pharo%20Smalltalk' asZnUrl. = 'http://www.google.com:80/search?q=Pharo Smalltalk' asZnUrl. Note how the ==ZnUrl== parser is forgiving with respect to the space, like most browser would do. When producing an external representation, proper encoding will take place. Please consult the class comment of ==ZnUrl== for a more detailed look at the capabilities of ==ZnUrl== as a standalone object. -!! ZnClient lifecycle +!!ZnClient lifecycle HTTP 1.1 defaults to keeping the client connection to a server open, and the server will do the same. This is useful and faster if you need to issue more than one request. ==ZnClient== implements this behavior by default. @@ -317,11 +318,11 @@ Array streamContents: [ :stream | | client | client close ]. ]]] -The above example sets up a client to connect to a specific host. Then it collects the results of 10 different requests, asking for random strings of a specific size. All request will go over the same network connection. +The above example sets up a client to connect to a specific host. Then it collects the results of 10 different requests, asking for random strings of a specific size. All requests will go over the same network connection. -Neither party is required to keep the connection open for a long time, as this consumes resources. Both parties should be prepared to deal with connections closing, this is not an error. ==ZnClient== will try to reuse an existing connection and reconnect once if this reuse fails. The option ==connectionReuseTimeout== limits how old a connection can be for reuse to be attempted. @@ to be reused? @@ +Neither party is required to keep the connection open for a long time, as this consumes resources. Both parties should be prepared to deal with connections closing, this is not an error. ==ZnClient== will try to reuse an existing connection and reconnect once if this reuse fails. The option ==connectionReuseTimeout== limits how old a connection can be for reuse to be attempted. @@to be reused? @@ -Note how we also close the client using the message ==close== @@?@@. A network connection is an external resource, like a file, that should be properly closed after use. If you don't do that, they will get cleaned up eventually by the system, but it is more efficient to do it yourself. +Note how we also close the client using the message ==close==. A network connection is an external resource, like a file, that should be properly closed after use. If you don't do that, they will get cleaned up eventually by the system, but it is more efficient to do it yourself. In many situations, you only want to do one single request. HTTP 1.1 has provisions for this situation. The beOneShot option of ==ZnClient== will do just that. @@ -331,9 +332,9 @@ ZnClient new get: 'http://zn.stfx.eu/numbers.txt'. ]]] -With the beOneShot option, the client notifies the server that it will do just one request and both parties will consequently close the connection after use, automatically. An explicit close of the ==ZnClient== object it no longer needed. +With the beOneShot option, the client notifies the server that it will do just one request and both parties will consequently close the connection after use, automatically. In this case, an explicit close of the ==ZnClient== object it no longer needed. -!! Basic Authentication +!!Basic Authentication There are various techniques to add authentication, a mechanism to control who accesses which resources, to HTTP. This is orthogonal to HTTP itself. The simplest and most common form of authentication is called 'Basic Authentication'. @@ -351,7 +352,7 @@ Note that when sending multiple requests while reusing the same client, authenti Beware that basic authentication is not the same as a web application where you have to log in using a form. See the subsection about cookies and sessions for an example of how this works. -!! Submitting HTML forms +!!Submitting HTML forms In many web applications HTML forms are used. Examples are forms to enter a search string, a form with a username and password to log in or complicated registration forms. In the classic and most common way, this is implemented by sending the data entered in the fields of a form to the server when a submit button is clicked. It is possible to implement the same behavior programmatically using ==ZnClient==. @@ -373,7 +374,7 @@ ZnClient new post. ]]] -The URL is composed by combining the URL of the page that contains the form with the action specified. The default form encoding is, as explicitly specified here, ==application/x-www-form-urlencoded== @@ where? by application/@@. By using the ==formAt:put:== method to set the value of a field, an entity of type ==ZnApplicationFormUrlEncodedEntity== will be created if needed, and the field name/value association will be stored in it. When finally ==post== is invoked, the HTTP request sent to the server will include a properly encoded entity. As far as the server is concerned, it will seem as if a real user submitted the form. Consequently, the response should be the same as when you submit the form manually using a browser. Be careful to include all relevant fields, even the hidden ones. +The URL is composed by combining the URL of the page that contains the form with the action specified. There is no need to set the encoding of the request here because the form uses the default encoding ==application/x-www-form-urlencoded==. By using the ==formAt:put:== method to set the value of a field, an entity of type ==ZnApplicationFormUrlEncodedEntity== will be created if needed, and the field name/value association will be stored in it. When finally ==post== is invoked, the HTTP request sent to the server will include a properly encoded entity. As far as the server is concerned, it will seem as if a real user submitted the form. Consequently, the response should be the same as when you submit the form manually using a browser. Be careful to include all relevant fields, even the hidden ones. There is a second type of form encoding called ==multipart/form-data==. Instead of adding fields, you add ==ZnMimePart== instances. The HTML form will specify a different enctype. @@ -384,7 +385,7 @@ There is a second type of form encoding called ==multipart/form-data==. Instead ]]] -The code to do the upload would then be as follows. @@ we talked about search before? now upload I'm getting confused@@ +The code to submit this form would then be as follows. [[[ ZnClient new @@ -413,7 +414,7 @@ ZnClient new Sometimes, the form's submit method is GET instead of POST, just send ==get== instead of ==post== to the client. Note that this technique of sending form data to a server is different than what happens with raw POST or PUT requests using a REST API. In a later subsection we will come back to this. -!! Cookies and sessions +!!Cookies and sessions HTTP is by design a stateless protocol: each request/response cycle is independent. This principle is crucial to the scalability of the internet. However, in web applications like a shopping cart in an online store, state is needed. During your interaction with the web application, the server needs to know that your request/responses are part of your session: you log in, you add items to your shopping cart and you finally check out and pay. It would be problematic if the server mixed the request/responses of different users. @@ -424,7 +425,7 @@ As we saw before, a ==ZnClient== instance is essentially stateful. It not only t Cookie handling will happen automatically. This is a hypothetical example of how this might work, assuming a site where you have to log in before you are able to access a specific file. [[[ -ZnClient +ZnClient new url: 'http://cloud-storage.com/login'; formAt: 'username' put: 'john.doe@acme.com'; formAt: 'password' put: 'trustno1'; @@ -432,9 +433,9 @@ ZnClient get: 'http://cloud-storage.com/my-file'. ]]] -After the ==post==, the server will presumably set a cookie to acknowledge a successful login. When a specific file is next requested from the same domain, the client presents the cookie to prove the login. The server knows it can send back the file because it recognizes the cookie as valid. By sending ==session== to the client object, you can access the remembered cookies. +After the ==post==, the server will presumably set a cookie to acknowledge a successful login. When a specific file is next requested from the same domain, the client presents the cookie to prove the login. The server knows it can send back the file because it recognizes the cookie as valid. By sending ==session== to the client object, you can access the session object and then the remembered cookies. -!! PUT and POST +!!PUT and POST A regular request for a resource is done using a GET request. A GET request does not send an entity to the server. The only way for a GET request to transfer information to the server is by encoding it in the URL, either in the path or in query variables. To be 100% correct we should add that data can be sent as custom headers as well. @@ -460,11 +461,11 @@ ZnClient new In the last example we explicitly set the entity to be XML and do a POST. In the first two examples, the convenience contents system is used to automatically create a ==ZnStringEntity== of type ==ZnMimeType textPlain== and a ==ZnByteArrayEntity== of type ==ZnMimeType applicationOctectStream==. -The difference between PUT and POST is semantic. POST is generally used to create a new resource inside an existing collection or container, or to initiate some action or process. For this reason, the normal response to a POST request is to return the URL (or URI) of the newly created resource. Conventionally, the response will contain a ==Location== header accessible via the message ==location== and will often repeat that @@what@@ in the entity it sends back. +The difference between PUT and POST is semantic. POST is generally used to create a new resource inside an existing collection or container, or to initiate some action or process. For this reason, the normal response to a POST request is to return the URL (or URI) of the newly created resource. Conventionally, the reponse contains this URL both in the ==Location== header accessible via the message ==location== and in the entity part. -When a POST successfully created the resource, its HTTP response will be 201 Created. PUT is generally used to update an existing resource of which you know the exact URL (of URI). When a PUT is successful, its HTTP response will be just 200 OK and nothing else will be returned. In the subsection about REST Web Service APIs, we will come back to this. +When a POST successfully created the resource, its HTTP response will be 201 Created. PUT is generally used to update an existing resource of which you know the exact URL (of @@?@@ URI). When a PUT is successful, its HTTP response will be just 200 OK and nothing else will be returned. In the subsection about REST Web Service APIs, we will come back to this. -!! DELETE and other HTTP methods +!!DELETE and other HTTP methods The fourth member of the common set of HTTP methods is DELETE. It is very similar to both GET and PUT: you just specify an URL of the resource that you want to delete or remove. When successful, the server will just reply with a 200 OK. That is all there is to it. @@ -478,13 +479,13 @@ ZnClient new response. ]]] -Since the OPTIONS request does not return an entity, but only meta data we access the response @@?? we get as return value the response instead?@@. Have a look at the ==Allow== header. +An OPTIONS request does not return an entity, but only meta data that are included in the header of the response. In this example, the response header contains an extra meta data named ==Allow== which specifies the list of HTTP methods that may be used on the resource. -!! Content-types, mime-types and the accept header +!!Content-types, mime-types and the accept header Just because you ask for some resource which you think is of a certain mime-type, does not yet mean that is what you will get back. The people maintaining the server might have reconfigured things. The extension at the end of a URL has no real significance. Asking for ==http://example.com/foo==, ==http://example.com/foo.txt== or ==http://example.com/foo.text== could all be the same or all be different. That is why HTTP resources (entities) are accompanied by a content-type, a mime-type that is an official, cross-platform definition of a file or document type or format. Again, see the Wikepedia article *Internet media type>http://en.wikipedia.org/wiki/Mime-type* for more details. -Zn models mime-types using its ==ZnMimeType== object which has 3 components +Zn models mime-types using its ==ZnMimeType== object which has 3 components: - a main type, for example text or image, - a sub type, for example plain or html, or jpeg, png or gif, and @@ -515,17 +516,17 @@ ZnClient new The above code indicates to the server that we want a ==text/plain== type resource by means of the ==Accept== header. When the response comes back and it is not of that type, the client will raise a ==ZnUnexpectedContentType== exception. Again, this will be handled by the ==ifFail:== block, when specified. This technique further improves your HTTP interaction. -!! Redirects +!!Redirects Sometimes when requesting a URL, an HTTP server will not answer immediately but redirect you to another location. Seaside actually does this on each request. This is done with a 301 or 302 response code. You can ask a ==ZnResponse== whether it's a redirect with ==isRedirect==. In case of a redirect response, the ==Location== header will contain the location the server redirects you to. You can access that URL using ==location==. By default, ==ZnClient== will follow redirects automatically for up to 3 redirects. You won't even notice unless you activate logging. -If for some reason you want to disable this feature, send a ==followRedirects:== false to your client. To modify the maximum number of redirects that could be followed, use ==maxNumberOfRedirects:==. +If for some reason you want to disable this feature, send a ==followRedirects: false== to your client. To modify the maximum number of redirects that could be followed, use ==maxNumberOfRedirects:==. Following redirects can be tricky when PUT or POST are involved. Zn implements the common behavior of changing a redirected PUT or POST into a GET while dropping the body entity. Cookies will be resubmitted. Zn also handles relative redirect URLs, although these are not strictly part of the standard. -!! ZnEasy, typing even less, accessing images as forms +!!ZnEasy, typing even less, accessing images as forms Although ==ZnClient== is absolutely the preferred object to deal with all the intricacies of HTTP, you sometimes wish you could to a quick HTTP request with an absolute minimum amount of typing, especially during debugging. For these occasions there is ==ZnEasy==, a class side only API for quick HTTP requests. @@ -533,7 +534,7 @@ Although ==ZnClient== is absolutely the preferred object to deal with all the in ZnEasy get: 'http://zn.stfx.eu/zn/numbers.txt'. ]]] -The result is always a ==ZnResponse== object. Apart from basic authentication, there are no other options. A nice feature here, more as an example, are some direct ways to ask for image resources as ready to use Forms. +The result is always a ==ZnResponse== object. Apart from basic authentication, there are no other options. A nice feature here, more as an example, is some direct ways to ask for image resources as ready to use Forms. [[[ ZnEasy getGif: 'http://homepage.mac.com/svc/ADayAtTheBeach/calculator.gif'. @@ -546,7 +547,7 @@ ZnEasy getPng: 'http://www.pharo-project.org/images/pharo.png'. When you explore the implementation, you will notice that ==ZnEasy== uses a ==ZnClient== object internally. -!! Headers +!!Headers HTTP meta data, both for requests and for responses, is specified using headers. These are key/value pairs, both strings. A large number of predefined headers exists, see this *List of HTTP header fields>http://en.wikipedia.org/wiki/HTTP_header*. The exact semantics of each header, especially their value, can be very complicated. @@ -562,7 +563,7 @@ ZnClient new request headers at: 'ACCEPT' put: 'text/*'. ZnClient new request headers at: 'accept' put: 'text/*'. ]]] -Once a request is executed, you can query the response headers like this +Once a request is executed, you can query the response headers like this: [[[ client response isConnectionClose. @@ -571,7 +572,7 @@ client response isConnectionClose. There is also the option to bulk transfer any keyedCollection holding a set of key/value pairs. -!! Just the meta data, please +!!Just the meta data, please HTTP provides for a way to do a request, just like a regular GET but with a response that contains only the meta data, the status line and headers, but not the actual resource or entity. This is called a HEAD request. @@ -581,11 +582,11 @@ ZnClient new response. ]]] -Since there is no contents, we have to look at the response object. Note that the content-type and content-length headers will be set, as if there was an entity, although none is transferred. +Since there is no content, we have to look at the response object. Note that the content-type and content-length headers will be set, as if there was an entity, although none is transferred. -!! Client options and policies +!!Client options and policies -To handle its large set of options, ==ZnClient== implements a uniform, generic option mechanism using the key methods ==optionAt:put:== and ==optionAt:ifAbsent:== (this last one always defines an explicit default), storing them lazily in a dictionary. The method category ==options== includes all accessor to actual settings. +To handle its large set of options, ==ZnClient== implements a uniform, generic option mechanism using the methods ==optionAt:put:== and ==optionAt:ifAbsent:== (this last one always defines an explicit default), storing them lazily in a dictionary. The method category ==options== includes all accessors to actual settings. Options are generally named after their accessor. An exception is ==beOneShot==. For example, the timeout option has a getter named ==timeout== and setter named ==timeout:== whose implementation defines its default @@ -606,7 +607,7 @@ self This kind of behavior is good practice when system level code does an HTTP call. -!! Entity hierarchy +!!Entity hierarchy By now we used almost all concrete subclasses of ==ZnEntity==: @@ -616,11 +617,11 @@ By now we used almost all concrete subclasses of ==ZnEntity==: - ==ZnMultiPartFormDataEntity== - ==ZnStreamingEntity== -Like all other fundamental Zn domain model objects, these can and are used both by client and servers. All ==ZnEntities== have a content type (a mime-type) and a content length (in bytes). Their basic behavior is that they can be written to or read from a binary stream. All but the last one are classic, in-memory objects. +Like all other fundamental Zn domain model objects, these can and are used both by clients and servers. All ==ZnEntities== have a content type (a mime-type) and a content length (in bytes). Their basic behavior is that they can be written to or read from a binary stream. All but the last one are classic, in-memory objects. ==ZnStreamingEntity== is special: it contains a read or write stream to be used once in one direction only. If you want to transfer a 10 Mb file, using a normal entity, this would result in the 10 Mb being taken into memory. With a streaming entity, a file stream is opened to the file, and the data is then copied using a buffer of a couple of tens of Kb. This is obviously more efficient. The limitation is that this only works if the exact size is known upfront. The subsection about streaming, uploading and downloading contains higher level examples of using ==ZnStreamingEntities==. -!! Content readers and writers +!!Content readers and writers As mentioned before, ==ZnMessages== (==ZnRequests== and ==ZnResponses==) can hold an optional ==ZnEntity== as body. In the subsection about the ==ZnEntity== hierarchy we saw that there are a couple of different types. But knowing that a ==ZnStringEntity== has a content type of XML or JSON is not enough to interpret the data correctly. diff --git a/pillar.conf b/pillar.conf index dd1f7e1..8d88d59 100644 --- a/pillar.conf +++ b/pillar.conf @@ -30,9 +30,9 @@ "Zinc-Encoding-Meta/Zinc-Encoding-Meta.pillar", "Zinc-REST/Zinc-REST.pillar", "PillarChap/Pillar.pillar", - "Artefact/Artefact.pillar", - "NativeBoostX11/NativeBoostX11.pillar", - "Fuel/Fuel.pillar", - "STON/STON.pillar" + "Artefact/Artefact.pillar", + "NativeBoostX11/NativeBoostX11.pillar", + "Fuel/Fuel.pillar", + "STON/STON.pillar" ] }