Permalink
Browse files

updated docs

  • Loading branch information...
1 parent 0435014 commit 59cc55644ea772b8d0d505e5d4e27db861f5419e @ostinelli committed Jan 29, 2012
Showing with 870 additions and 250 deletions.
  1. +129 −0 CHANGELOG.md
  2. +590 −0 EXPORTS.md
  3. +151 −0 README.md
  4. +0 −250 README.txt
View
129 CHANGELOG.md
@@ -0,0 +1,129 @@
+# CHANGELOG
+
+### 0.9:
+ * added SESSIONS state, persistent across requests
+ * added access log callback function, so that main application can log HTTP access
+ * added streaming input for big files or endless input, using a manual ```body_recv function``` in conjunction with the ```{auto_recv_body, false}``` option
+ * added static directory support, so that GET requests to /static/* can automatically send files from a specified directory (thanks to egobrain suggestion)
+ * added request redirection helper method
+ * consistently improved memory usage by not copying by default to handler processes the full request or websocket record
+ * added configuration option to set which websocket versions must be supported by the server
+ * added support for websocket draft-hybi-10
+ * added support for websocket draft-hybi-17 (thanks to RJ)
+ * added support for websockets on FireFox (thanks to Egobrain)
+ * added support for 'If-Modified-Since' headers in file sending (thanks to davidgaleano)
+ * added support for websockets when behind stunnel with ```{external_ssl, boolean()}``` option (thanks to RJ)
+ * added support to see the correct client IP when behind stunnel, according to http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt (thanks to RJ)
+ * added support for OPTIONS method (thanks to majek)
+ * rebar-ized makefile
+ * corrected minor bugs (thank you all - you know who you are!)
+
+### 0.8:
+ * Misultin has been redesigned to use supervisor behaviours where appropriate, to be more OTP compliant
+ * added Cookie support
+ * added preliminary support multipart/form-data and a file upload example (thanks to Max Lapshin)
+ * added Date and Server headers
+ * added support for headers being specified as binaries (thanks to akaspin)
+ * added an example on how to properly embed misultin in your application
+ * ```Req:get(peer_addr)``` now properly extracts peer information from headers "X-Real-Ip" or "X-Forwarded-For" if these are available (thanks to Max Lapshin)
+ * solved bug on large data being sent over via websockets (thanks to omarkj)
+ * corrected binary sending bug in websockets which would fail binaries on io_lib format (thanks to normanb)
+ * added recbuf advanced option (issue #40)
+ * added preliminary test suite
+ * various optimizations using binary when needed
+
+### 0.7.1:
+ * considerably improved stability under heavy load
+ * misultin now accepts incoming connections with a pool of acceptors instead of a single one
+ * Misultin can now be used both with parametrized modules and with pure erlang code too (thanks to yrashk, nox and essen)
+ * added support for HEAD, PUT, DELETE, TRACE and CONNECT methods
+ * now websockets are on ```{active, once}``` mode to avoid malicious clients overflooding (thanks to essen)
+ * ensured that body of request can be read on all methods except TRACE as per http specs
+ * added support for iolist() in chunked resposes (thanks to RJ)
+
+### 0.7:
+ * added ```max_connections options``` parameter, which specifies maximum concurrent open connections accepted by the server
+ * added ```post_max_size``` options parameter, which sets the maximum size of POST data
+ * added ```get_url_max_size``` options parameter, which sets the maximum length of URI
+ * added CHUNKED support, both for incoming requests and outgoing responses (thanks to yrashk suggestion)
+ * added trapping of client closing a browser in Comet applications (thanks to yrashk)
+ * added SSL support for websockets (enhancement track #25, thanks to viplifes)
+ * Misultin can now be started without a registered name or with a different name, so that multiple versions of misultin can be started on a single node
+ * added support for IP address specified in tuple format (thanks to okeuday suggestion)
+ * added support to extract plain uri unquoted as a list() (thanks to okeuday)
+ * added Comet Long Polling example
+ * added Comet iFrame example
+ * added the killing of alive processes on server shutdown
+ * the GET uri parameters are now also available on POST requests
+ * added custom headers on file sending to browser (thanks to josevalim)
+ * additional minor adjustments
+
+### 0.6.2:
+ * refactored to considerably improve sending of static files
+ * minor bug corrections
+
+### 0.6.1:
+ * added support to websocket protocol hixie draft 76 (thanks to sergio veiga)
+ * added support to multiple websocket draft protocols (for backwards compatibility)
+ * added ```ws_autoexit option``` which allows to get an event on websocket controlling processes (issue track #15, suggestion of esente)
+ * added headers also in misultin websockets (thanks to jlirochon)
+ * made it basho's rebar friendly (thanks to mrinalwadhwa)
+
+### 0.6:
+ * added HTTP compression option
+ * refactoring of the main server loop, so that it is now isolated from the HTTP functionality
+ * removed unnecessary compilation warnings
+ * replaced ```proplists:get_value``` with much faster utility function
+
+### 0.5:
+ * added SSL support
+ * refactoring of the acceptor loop
+
+### 0.4:
+ * added preliminary websocket support
+
+### 0.3.4:
+ * added Req support to return the socket handling the request
+ * bug correction on Content-Length: 0 header causing timeout on POST requests (issue track #12, thanks to gdamjan)
+
+### 0.3.3:
+ * added echoing of the Connection header (issue track #7, thanks to thijsterlouw)
+ * bug correction on acceptor respawning (issue track #10, thanks to thijsterlouw)
+
+### 0.3.2:
+ * optimized error handling (issue track #5, thanks to Max Lapshin)
+
+### 0.3.1:
+ * added flow control using inet options {active, once} (issue track #4, thanks to Max Lapshin)
+ * added support to standard http headers response
+ * added http 400 bad request error in socket handling
+ * bug correction: removed erroneous sending of response timeout on listening open connections
+ * added stream_support optimization option
+
+### 0.3:
+ * reengineering of the listener process, using active instead of passive mode in request parsing, except for BODY where passive is still used (thanks to Lev Walkin)
+ * added better support for request timeout
+
+### 0.2.2:
+ * added .app file (thanks to Essien Ita Essien)
+ * simplified get_options (thanks to Essien Ita Essien)
+ * added ip address option (thanks to Essien Ita Essien)
+ * added ipv6 support
+ * added ```recv_timeout``` option
+ * bug correction: requests peer address and port are now not reset on open connections multiple requests
+
+### 0.2.1:
+ * added support for Content-Type that specifies charset in POST data (thanks to Tuncer Ayaz)
+ * added support for iolist in ```misultin_req:ok/1,2``` and ```misultin_req:respond/2,3```
+ * code optimized taking out unnecessary binary conversion and lists:flatten (thanks to Feng Yu)
+
+### 0.2:
+ * added trap exit for acceptor failure
+ * added backlog option
+ * added fallback if no connection header is present (issue track #1, thanks to Ciconia)
+ * added limit for parsing headers to avoid malicious attacks (thanks to Mazen Harake)
+ * minor bug corrections
+
+### 0.1:
+ * initial release.
+
View
590 EXPORTS.md
@@ -0,0 +1,590 @@
+# Misultin modules list of exports
+
+# 1. misultin #
+
+## Description ##
+
+This module contains the necessary functionalities to manage the misultin HTTP server.
+
+## Exports ##
+
+### start_link(Options) -> {ok, pid()} | {error, term()} ###
+```erlang
+
+Options = [Option]
+ Option = {ip, list() | tuple()} |
+ {port, integer()} |
+ {name, atom()} |
+ {backlog, integer()} |
+ {recbuf, integer()} |
+ {acceptors_poolsize, integer()} |
+ {recv_timeout, integer()} |
+ {max_connections, integer()} |
+ {loop, fun()} |
+ {autoexit, true|false} |
+ {ws_loop, fun()|none} |
+ {ws_autoexit, true|false} |
+ {ws_versions, WsVersions()} |
+ {post_max_size, integer()} |
+ {get_url_max_size, integer()} |
+ {compress, boolean()} |
+ {ssl, SslOptions} |
+ {ws_force_ssl, boolean()} |
+ {proxy_protocol, boolean()} |
+ {sessions_expire, integer()} |
+ {access_log, fun()} |
+ {auto_recv_body, boolean()} |
+ {static, boolean()}
+ SslOptions = [SslOption(§)]
+ WsVersions = ['draft-hybi-17', 'draft-hybi-10', 'draft-hixie-76', 'draft-hixie-68']
+Result = {ok, Pid} | ignore | {error, Error}
+ Pid = pid()
+ Error = {already_started,Pid} | term()
+```
+
+(§) `SslOption` is defined as a [ssl_new option](http://www.erlang.org/doc/man/new_ssl.html#id2263736).
+
+Starts the misultin gen_server. Options are:
+
+* *ip*: the IP address of the HTTP server. Can be expressed as string "0.0.0.0" or as tuple {0,0,0,0}. Defaults to "0.0.0.0".
+* *port*: an integer specifying the port number where the HTTP server will run, defaults to 80
+* *name*: an atom specifying the registered name of misultin. If set to false, misultin will start with no registered name. Defaults to 'misultin'.
+* *backlog*: defines the maximum length that the queue of pending connections may grow to, defaults to 128
+* *recbuf*: defines the size of the receiving buffer
+* *acceptors_poolsize*: defines the acceptors' pool size. Defaults to 10.
+* *recv_timeout*: defines the receive timeout on incoming TCP data, defaults to 30000 (30 seconds)
+* *max_connections*: sets the maximum number of concurrent connections that the server is willing to handle, defaults to 1024
+* *loop*: the callback function to be called on every incoming HTTP request
+* *autoexit*: if set to true, then the loop specified as loop will be killed automatically by the server when the client closes the socket; if set to false, an event message is sent to loop which then needs to be exited in the most appropriate way.
+* *ws_loop*: the loop of the listening process which handles a websocket. If a function is passed as `ws_loop` option then websockets requests will be treated, they will be ignored. The function passed as ws_loop is spawned by misultin to handle the connected websockets. Data coming from a browser will be sent to this process and will have the message format {browser, Data}, where Data is a list(). If you need to send data to the browser, you may do so by using the parametrized function Ws:send(Data), Data being a list() or an iolist() (see the [[ExamplesPage]]). Defaults to `none`.
+* *ws_autoexit*: if set to true, then the loop specified as ws_loop will be killed automatically by the server when the socket closes; if set to false, an event message is sent to ws_loop which then needs to be exited in the most appropriate way.
+* *ws_versions*: sets the accepted Websocket protocol versions. Defaults to `['draft-hybi-17', 'draft-hybi-10', 'draft-hixie-76']`.
+* *compress*: set to `true` to send responses in compressed format, if available. Please note that files sent with `Req:file/1,2` and stream with `Req:stream/1,2,3` will not be compressed.
+* *post_max_size*: sets the maximum size in bytes of a POST request body. Defaults to 4MB.
+* *get_url_max_size*: sets the maximum length of the URI of a request. Defaults to `2000`.
+* *compress*: sets if compression is to be used in responses, when available. Defaults to `false`.
+* *ssl*: allows to start Misultin in SSL mode. Parameter is a list of [ssl_new options](http://www.erlang.org/doc/man/new_ssl.html#id2263736).
+* *ws_force_ssl*: if you are running misultin behind an SSL terminator such as stunnel or stud, and are using websockets, to make the websocket handshakes work you should set this option to `true`. Defaults to `false`.
+* *proxy_protocol*: if you are using stunnel to terminate, to make misultin expect a PROXY.. line as per the [proxy protocol](http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt) you can set this option to `true`. Defaults to `false`.
+* *sessions_expire*: the timeout in seconds of when session variables should expire. Defaults to 600.
+* *access_log*: a custom access log callback function. Defaults to undefined.
+* *auto_recv_body*: sets if the body should be automatically read by misultin (`true`) or if it should be explicitly called in callback functions for more advanced functionalities (`false`). Defaults to `true`.
+* *static*: if set to `{true, "my/dir/here}"` all URI pointing at http://myserver/static/ will be serving the files in the specified directory. Defaults to `false`.
+
+The example here below starts a Misultin HTTP server on port 8080, and sets all incoming HTTP requests to be treated by a function `handle_http/1`:
+
+```erlang
+
+misultin:start_link([{port, 8080}, {loop, fun(Req) -> handle_http(Req) end}]).
+```
+
+### stop() -> true ###
+
+Stops the misultin gen_server.
+
+Example to stop the Misultin HTTP server:
+
+```erlang
+
+misultin:stop().
+```
+
+### stop(ServerRef) -> true ###
+
+Stops the misultin gen_server when the name option has been defined.
+
+Example to start and stop a Misultin HTTP server started without a registered name:
+
+```erlang
+
+{ok, ServerPid} = misultin:start_link([{port, 8080}, {name, false}, {loop, fun(Req) -> handle_http(Req) end}]),
+misultin:stop(ServerPid).
+```
+
+# 2. Misultin Request #
+
+## Description ##
+
+This module contains the necessary functionalities to manage the incoming HTTP requests and provide a response. This module uses Erlang parametrized modules, therefore the syntax is to be understood accordingly.
+
+## Exports ##
+
+### Req:body_recv(head) -> {ok, binary()} | {chunk, binary()} | end_of_chunks | {error, term()} ###
+
+If misultin was started with the `{auto_body_recv, false}` option, then this function allows you to receive the body of a request. If the received body is not chunked, the body will be returned as `{ok, Body}`. If the body is chunked, all the chunks will be returned as `{chunk, Body}` until `end_of_chunks` is received.
+
+### Req:chunk(head) ###
+
+Same as `Req:chunk(head, [])`.
+
+### Req:chunk(head, Headers) ###
+```erlang
+
+Headers = {Header]
+ Header = {HeaderName, HeaderContent}
+ HeaderName = atom()
+ HeaderContent = list()
+```
+
+Starts an HTTP response with chunked content.
+
+`HeaderName` is the name of the HTTP header field; `HeaderContent` is the content of the header.
+
+The functions `chunk/1,2,3` are used when the HTTP response has to be given progressively using chunked transfer encoding, and not altogether as it happens in `respond/2,3,4`.
+
+In order to provide a chunked HTTP response, these functions have to be used in a specific manner, as shown in this example:
+
+```erlang
+
+% send headers
+Req:chunk(head, [{"Content-Type", "text/html"}]),
+% send chunk
+Req:chunk("Sending CHUNK 1<br/>"),
+timer:sleep(2000),
+% send chunk
+Req:chunk("Sending CHUNK 2<br/>"),
+timer:sleep(2000),
+% send chunk
+Req:chunk("Sending CHUNK 3<br/>"),
+% close
+Req:chunk(done).
+```
+
+This will start a 200 HTTP response of text/plain Content-Type and send 3 chunks in sequence.
+
+### Req:chunk(Template) ###
+```erlang
+
+Template = atom() | list() | binary() | iolist()
+```
+
+Sends data chunk into the open HTTP socket.
+
+### Req:chunk(Template, Vars) ###
+```erlang
+
+Template = list()
+Vars = [term()]
+```
+
+Sends data into the open HTTP socket.
+
+`Template` and `Vars` build a character list which represents `Vars` formatted in accordance with `Template`. See <http://erlang.org/doc/man/io.html#format-3 io:format/3> for a detailed description of the available formatting options. A fault is generated if there is an error in the format string or argument list.
+
+### Req:chunk(done) ###
+
+Ends the Chunked sequence.
+
+### Req:get_cookies() -> [{CookieTag, CookieValue}] ###
+
+Retrieve all the cookies from the Cookie header in a proplist format.
+
+### Req:get_cookie_value(CookieName, Cookies) -> string() ###
+
+Retrieve the cookie value from the Cookies list.
+
+### Req:set_cookie(CookieName, CookieVal) -> ok ###
+
+Sets a cookie value in the headers of the response. Typical usage is:
+
+```erlang
+
+Req:ok([Req:set_cookie("misultin_test_cookie", "value of the test cookie", [{max_age, 365*24*3600}])],
+ "A cookie has been set. Refresh the browser to see it.");
+```
+
+### Req:delete_cookie(CookieName) -> ok ###
+
+Deletes a cookie. Typical usage is:
+
+```erlang
+
+Req:ok([Req:delete_cookie("misultin_test_cookie")],
+ ["The set cookie value was set to \"", CookieVal,"\", and has now been removed. Refresh the browser to see this."])
+```
+
+### Req:file(FilePath) ###
+```erlang
+
+FilePath = list()
+```
+
+Same as `Ref:file(FilePath, [])`.
+
+### Req:file(FilePath, Headers) ###
+```erlang
+
+FilePath = list()
+Headers = {Header]
+ Header = {HeaderName, HeaderContent}
+ HeaderName = atom()
+ HeaderContent = list()
+```
+
+Sends a file to be visualized in a browser, for example:
+
+```erlang
+
+Req:file("/usr/local/files/content.html").
+```
+
+### Req:file(attachment, FilePath) ###
+```erlang
+
+FilePath = list()
+```
+
+Same as `Ref:file(attachment, FilePath, [])`.
+
+### Req:file(attachment, FilePath, Headers) ###
+```erlang
+
+FilePath = list()
+Headers = {Header]
+ Header = {HeaderName, HeaderContent}
+ HeaderName = atom()
+ HeaderContent = list()
+```
+
+Sends a file as an attachment (so that a browser prompts for download), for example:
+
+```erlang
+
+Req:file(attachment, "/usr/local/files/test.zip").
+```
+
+### Req:get(ReqInfo) -> term() ###
+```erlang
+
+ReqInfo = socket |
+ socket_mode |
+ peer_addr |
+ peer_port |
+ peer_cert |
+ connection |
+ content_length |
+ vsn |
+ method |
+ uri |
+ uri_unquoted |
+ args |
+ headers |
+ body
+```
+
+Retrieves the Request information. See `Req:raw/0` for additional information on the output format. 'uri_unquoted' returns the plain uri unquoted as a list().
+
+### Req:ok(Template) ###
+
+Same as `Req:ok([], Template)`.
+
+### Req:ok(Headers, Template) ###
+
+Same as `Req:respond(200, Headers, Template)`.
+
+### Req:ok(Headers, Template, Vars) ###
+
+Same as `Req:respond(200, Headers, Template, Vars)`.
+
+### Req:options(Options) -> ok ###
+```erlang
+
+Options = [Option]
+ Option = {OptionTag, OptionValue}
+ OptionTag = comet
+ OptionValue = true | false
+```
+
+Sets advanced per-request options. Currently only the 'comet' option is supported. It is to be used in [Comet](http://en.wikipedia.org/wiki/Comet_%28programming%29) applications to allow for the trapping of clients remotely closing their tcp connection. You may call it at the top of the function handling your incoming http requests, like this:
+
+`Req:options([{comet, true}])`
+
+When setting this option, the server will consider that you are using comet techniques (such as long polling), which are [Server Push](http://en.wikipedia.org/wiki/Push_technology) techniques. Hence, the server will not expect any other incoming Http requests from the client on the same socket. If such requests are received after setting the comet option to true, the server will raise an error and close the socket.
+
+Set this option only on comet applications, otherwise [Http Pipelining](http://en.wikipedia.org/wiki/Http_pipelining) will not be supported.
+
+### Req:parse_post() -> Result ###
+```erlang
+
+Result = [Argument]
+ Argument = {ArgumentName, ArgumentValue}
+ ArgumentName = list()
+ ArgumentValue = list()
+```
+
+Parses the arguments passed in the body of the Request, when method is 'POST' and the Request _Content-Type_ header has been specified as _application/x-www-form-urlencoded_.
+
+
+### Req:parse_qs() -> Result ###
+```erlang
+
+Result = [Argument]
+ Argument = {ArgumentName, ArgumentValue}
+ ArgumentName = list()
+ ArgumentValue = list()
+```
+
+Parses the arguments passed in the querystring, when method is 'GET'.
+
+### Req:raw() -> record() ###
+
+Retrieves the Request complete record, defined as follows:
+```erlang
+
+-record(req, {
+ socket, % the socket handling the request
+ socket_mode, % http | ssl
+ peer_addr, % IP | undefined
+ peer_port, % Port | undefined
+ peer_cert, % undefined | the DER encoded peer certificate
+ connection = keep_alive, % keep_alive | close
+ content_length, % integer()
+ vsn, % {Maj, Min}
+ method, % 'GET' | 'POST'
+ uri, % {UriType, Uri}
+ args = "", % list()
+ headers, % [{Tag, Val}]
+ body = <<>> % bytes()
+}).
+```
+
+To use this record in your own code, you will need to include the file _misultin.hrl_. We recommend using the appropriate function `Req:get/1`, since additional operations are performed then such as Uri checks.
+
+### Req:redirect(Url) ###
+
+Redirect temporarily to the specified Url.
+
+### Req:redirect(permanent, Url) ###
+
+Redirect permanently to the specified Url.
+
+### Req:resource(Options) -> Resources ###
+```erlang
+
+Options = [Option]
+ Option = lowercase | urldecode
+Resources = [Resource]
+ Resource = list()
+```
+
+This functionality provides support for RESTful services built with Misultin. It will split the URI into the list of its resources (i.e. it will separate the URI with the / token).
+
+It also allows to provide two options:
+
+* *lowercase*: convert all resources to lowercase;
+* *urldecode*: decode urlencoded characters.
+
+See the ExamplesPage for a more detailed usage of this function.
+
+### Req:respond(HttpCode, Template) ###
+
+Same as `Req:respond(HttpCode, [], Template)`.
+
+### Req:respond(HttpCode, Headers, Template) ###
+```erlang
+
+HttpCode = integer()
+Headers = {Header]
+ Header = {HeaderName, HeaderContent}
+ HeaderName = atom()
+ HeaderContent = list()
+Template = atom() | list() | binary() | iolist()
+```
+
+Formats an HTTP response of code `HttpCode`.
+
+`HeaderName` is the name of the HTTP header field; `HeaderContent` is the content of the header.
+
+This example formats a static XML response:
+
+```erlang
+
+Req:respond(200, [{"Content-Type", "text/xml"}], "<misultin_test>ok</misultin_test>").
+```
+
+This example formats an XML response with the content of a parameter `Value`, using an `iolist()`:
+
+```erlang
+
+Req:respond(200, [{"Content-Type", "text/xml"}], ["<misultin_test><value>", Value, "</value></misultin_test>"]).
+```
+
+
+### Req:respond(HttpCode, Headers, Template, Vars) ###
+```erlang
+
+HttpCode = integer()
+Headers = {Header]
+ Header = {HeaderName, HeaderContent}
+ HeaderName = atom()
+ HeaderContent = list()
+Template = list()
+Vars = [term()]
+```
+
+Formats an HTTP response of code `HttpCode`.
+
+`HeaderName` is the name of the HTTP header field; `HeaderContent` is the content of the header.
+
+`Template` and `Vars` build a character list which represents `Vars` formatted in accordance with `Template`. See <http://erlang.org/doc/man/io.html#format-3 io:format/3> for a detailed description of the available formatting options. A fault is generated if there is an error in the format string or argument list.
+
+This example formats an XML response with the content of a parameter `Value`:
+
+```erlang
+
+Req:respond(200, [{"Content-Type", "text/xml"}], "<misultin_test><value>~s</value></misultin_test>", [Value]).
+```
+
+### Req:session() -> {SessionId, SessionState} | {error, Reason} ###
+
+Starts or retrieves an existing session, returning the SessionId and the SessionState. SessionState defaults to an empty array `[]`.
+
+### Req:session(Cookies) -> {SessionId, SessionState} | {error, Reason} ###
+
+Same as `Req:session/1` but if Cookies have already been parsed and are available, this allows a performance increase.
+
+### Req:session(SessionId, SessionState) -> ok | {error, Reason} ###
+
+Saves the new SessionState for a SessionId.
+
+### Req:stream(head) ###
+
+Same as `Req:stream(head, 200, [])`.
+
+### Req:stream(head, Headers) ###
+
+Same as `Req:stream(head, 200, Headers)`.
+
+### Req:stream(head, HttpCode, Headers) ###
+```erlang
+
+HttpCode = integer()
+Headers = {Header]
+ Header = {HeaderName, HeaderContent}
+ HeaderName = atom()
+ HeaderContent = list()
+```
+
+Starts an HTTP response of code `HttpCode`.
+
+`HeaderName` is the name of the HTTP header field; `HeaderContent` is the content of the header.
+
+The functions `stream/1,2,3` are used when the HTTP response has to be given progressively, and not altogether as it happens in `respond/2,3,4`.
+
+In order to provide a 'streamed' HTTP response, these functions have to be used in a specific manner, as shown in this example:
+
+```erlang
+
+% send headers
+Req:stream(head, [{"Content-Type", "text/plain"}]),
+% send stream
+Req:stream("1"),
+timer:sleep(2000),
+% send stream
+Req:stream("2"),
+timer:sleep(2000),
+% send stream
+Req:stream("3"),
+% close socket
+Req:stream(close).
+```
+
+This will start a 200 HTTP response of text/plain Content-Type and immediately send the character `1`. It will then wait 2 seconds, before sending character `2`. Finally, it will wait another 2 seconds before sending the last character `3` and close the socket.
+
+Basically, the `stream/1,2,3` functions work by providing all HTTP headers with the exception of _Content-Length_, which would otherwise allow the HTTP client to close the socket when all data is received. Therefore, the HTTP client keeps on listening since it doesn't know how much bytes it is supposed to receive, and thus it can be sent data progressively. Finally, however, since in this example no Content-Length header has been set, the closing of the socket needs to be done server-side, and thus the use of the function `Req:stream(close)`.
+
+### Req:stream(Template) ###
+```erlang
+
+Template = atom() | list() | binary() | iolist()
+```
+
+Sends data into the open HTTP socket.
+
+### Req:stream(Template, Vars) ###
+```erlang
+
+Template = list()
+Vars = [term()]
+```
+
+Sends data into the open HTTP socket.
+
+`Template` and `Vars` build a character list which represents `Vars` formatted in accordance with `Template`. See <http://erlang.org/doc/man/io.html#format-3 io:format/3> for a detailed description of the available formatting options. A fault is generated if there is an error in the format string or argument list.
+
+### Req:stream(close) ###
+
+Server-side closes the open socket. If Content-Length has NOT been specified, the socket must manually be closed by calling `Req:stream(close)`.
+
+### Req:stream({error, Reason}) ###
+
+If an error occurred when dealing with streams, you may call this function to terminate the connection and log the error.
+
+### Req:uri_unquote(Uri) -> UnquotedUri ###
+
+Convert Uri format into a string().
+
+# 3. Misultin Websockets #
+
+## Description ##
+
+This module contains the necessary functionalities to manage websockets. For the draft websocket protocol, you may refer to <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76>. This module uses Erlang parametrized modules, therefore the syntax is to be understood accordingly.
+
+## Exports ##
+
+### Ws:get(WsInfo) -> term() ###
+```erlang
+
+WsInfo = socket | socket_mode | peer_addr | peer_port | peer_cert | vsn | origin | host | path | headers
+```
+
+Retrieves the Websocket information. See `Ws:raw/0` for additional information on the output format.
+
+### Req:get_cookies() -> [{CookieTag, CookieValue}] ###
+
+Retrieve all the cookies from the Cookie header in a proplist format.
+
+### Req:get_cookie_value(CookieName, Cookies) -> string() ###
+
+Retrieve the cookie value from the Cookies list. Note that being in a websocket, cookies cannot be set or deleted unless some specific javascript gets evaluated on the client browser. Therefore, these functionalities cannot be provided as part of the websocket module and have to be implemented accordingly, if needed.
+
+### Ws:raw() -> record() ###
+
+Retrieves the Websocket complete record, defined as follows:
+```erlang
+
+-record(req, {
+ socket, % the socket handling the websocket
+ socket_mode, % http | ssl
+ peer_addr, % IP | undefined
+ peer_port, % Port | undefined
+ peer_cert, % undefined | the DER encoded peer certificate
+ vsn, % {Maj,Min} | {'draft-hixie', Ver}
+ origin, % the originator
+ host, % the host
+ path, % the websocket GET request path
+ headers % [{Tag, Val}]
+}).
+```
+
+To use this record in your own code, you will need to include the file _misultin.hrl_. We recommend using the appropriate function `Ws:get/1`, since additional operations are performed then such as Uri checks.
+
+### Ws:send(Data) ###
+```erlang
+
+Data = list() | iolist()
+```
+
+Sends data into the open Websocket to the recipient browser. For additional information, see the [[ExamplesPage]].
+
+### Req:session() -> {SessionId, SessionState} | {error, Reason} ###
+
+Starts or retrieves an existing session, returning the SessionId and the SessionState. SessionState defaults to an empty array `[]`.
+
+### Req:session(Cookies) -> {SessionId, SessionState} | {error, Reason} ###
+
+Same as `Req:session/1` but if Cookies have already been parsed and are available, this allows a performance increase.
+
+### Req:session(SessionId, SessionState) -> ok | {error, Reason} ###
+
+Saves the new SessionState for a SessionId.
View
151 README.md
@@ -0,0 +1,151 @@
+# MISULTIN
+
+Misultin is an HTTP(S) library which can easily be embedded in your own application.
+
+https://github.com/ostinelli/misultin
+
+`>-|-|-(°>`
+
+
+# Features
+
+ * _Very_ fast
+ * HTTP and HTTPS
+ * Supports multiple **Websocket** protocols (draft-hixie-68, draft-hixie-76, draft-hybi-10 and draft-hybi-17)
+ * **Cookies**
+ * **Session** Variables
+ * Allows for Chunked and Byte **streaming responses**
+ * Allows for **streaming file upload** (via Chunked Encoding)
+ * Can serves static files from a ```static``` directory (though in production you should consider a specific server such as [nginx](http://nginx.org/) to do so)
+ * Has Many customization options (maximum allowed connections, maximum body size, ...)
+ * Has a callback function for your **logging** needs
+ * Supports **Unicode**
+ * Can start multiple servers on a single node
+ * Can be used with or without Parametrized Modules
+ * Can traps the client closing a browser in Comet applications
+ * It's very easy to use
+
+
+# Quick Start
+
+ The typical 'Hello World" example code is:
+
+```erlang
+
+-module(misultin_hello_world).
+-export([start/0, stop/0]).
+
+% start misultin http server
+start() ->
+ misultin:start_link([{port, 8080}, {loop, fun(Req) -> handle_http(Req) end}]).
+
+% stop misultin
+stop() ->
+ misultin:stop().
+
+% callback on request received
+handle_http(Req) ->
+ Req:ok("Hello World.").
+```
+
+Issuing the ```start/0``` command will start an HTTP server on port 8080, which will respond to every request with an "Hello World" text.
+
+# Examples
+
+Misultin comes [packed with examples](https://github.com/ostinelli/misultin/tree/master/examples/).
+
+#### Simple Examples
+
+ * [Hello World](https://github.com/ostinelli/misultin/tree/master/examples/misultin_hello_world.erl)
+ * [Querystring Variables](https://github.com/ostinelli/misultin/tree/master/examples/misultin_get_variable.erl)
+ * [Querystring and POST Variables](https://github.com/ostinelli/misultin/tree/master/examples/misultin_echo.erl)
+ * [REST](https://github.com/ostinelli/misultin/tree/master/examples/misultin_rest.erl)
+ * [Set and Get Cookies](https://github.com/ostinelli/misultin/tree/master/examples/misultin_cookies_example.erl)
+ * [Set and Get Session Variables](https://github.com/ostinelli/misultin/tree/master/examples/misultin_sessions_example.erl)
+ * [Serve a Static file for download](https://github.com/ostinelli/misultin/tree/master/examples/misultin_file.erl)
+ * [Serving files from a Static directory](https://github.com/ostinelli/misultin/tree/master/examples/misultin_static.erl)
+ * [File Upload](https://github.com/ostinelli/misultin/tree/master/examples/misultin_file_upload.erl)
+ * [HTTPS example](https://github.com/ostinelli/misultin/tree/master/examples/misultin_ssl.erl)
+ * [Performing a simple redirection](https://github.com/ostinelli/misultin/tree/master/examples/misultin_redirect.erl)
+ * [Serving compressed content](https://github.com/ostinelli/misultin/tree/master/examples/misultin_compress.erl)
+ * [Logging Access](https://github.com/ostinelli/misultin/tree/master/examples/misultin_access_log.erl)
+
+#### Websockets
+
+ * [Simple Websocket](https://github.com/ostinelli/misultin/tree/master/examples/misultin_websocket_example.erl)
+ * [Simple Websocket on SSL](https://github.com/ostinelli/misultin/tree/master/examples/misultin_websocket_example_ssl.erl)
+ * [Websocket exposing the close event](https://github.com/ostinelli/misultin/tree/master/examples/misultin_websocket_event_example.erl)
+ * [Websocket exposing the close event, example 2](https://github.com/ostinelli/misultin/tree/master/examples/misultin_websocket_event_example2.erl)
+ * [Access Session Variables from Websockets](https://github.com/ostinelli/misultin/tree/master/examples/misultin_websocket_sessions_example.erl)
+
+
+#### Comets
+
+ * [Long Polling](https://github.com/ostinelli/misultin/tree/master/examples/misultin_comet_long_polling.erl)
+ * [iFrame Technique](https://github.com/ostinelli/misultin/tree/master/examples/misultin_comet_iframe.erl)
+ * [iFrame Technique using the close event](https://github.com/ostinelli/misultin/tree/master/examples/misultin_comet_iframe_event.erl)
+
+
+#### More Advanced
+
+ * [Sending Chunked Content](https://github.com/ostinelli/misultin/tree/master/examples/misultin_chunked.erl)
+ * [Sending Byte Streaming Content](https://github.com/ostinelli/misultin/tree/master/examples/misultin_stream.erl)
+ * [Receiving endless streaming Upload](https://github.com/ostinelli/misultin/tree/master/examples/misultin_body_recv.erl)
+ * [Unicode](https://github.com/ostinelli/misultin/tree/master/examples/misultin_unicode.erl)
+ * [REST with UTF-8](https://github.com/ostinelli/misultin/tree/master/examples/misultin_rest_utf8.erl)
+ * [Starting a nameless server](https://github.com/ostinelli/misultin/tree/master/examples/misultin_hello_world_nameless.erl)
+ * [Starting multiple servers on a same node, with a custom name](https://github.com/ostinelli/misultin/tree/master/examples/misultin_multiple_servers_custom_name.erl)
+ * [Using the HAProxy protocol](https://github.com/ostinelli/misultin/tree/master/examples/misultin_proxy_protocol.erl)
+
+# Module Exports
+
+The complete list of module exports can be found [here](https://github.com/ostinelli/misultin/tree/master/EXPORTS.md).
+
+# Parametrized modules
+
+Some developers hate them, some love them. Misultin allows you to choose if you want to use them or not. The same **Hello World** example shown here above, but without parametrized modules, looks like this:
+
+```erlang
+
+-module(misultin_hello_world).
+-export([start/0, stop/0]).
+
+% start misultin http server
+start() ->
+ misultin:start_link([{port, 8080}, {loop, fun(Req) -> handle_http(Req) end}]).
+
+% stop misultin
+stop() ->
+ misultin:stop().
+
+% callback on request received
+handle_http(Req) ->
+ misultin_req:ok("Hello World.", Req).
+```
+
+# Dependencies
+
+You will need:
+
+ * Erlang >= R14B01
+ *
+
+# Under the hood
+Misultin is built using the OTP principles. When you start it using the ```misultin:start_link/1``` command, you are actually starting a supervisor which handles all of Misultin's servers and modules.
+
+Therefore, in real life applications you should always embed it in your own application. An easy example on how this can be done can be found in the Application Example [here](https://github.com/ostinelli/misultin/tree/master/examples/application).
+
+# SSL Notes
+
+If you are running misultin behind an SSL terminator such as stunnel or stud, and are using websockets, to make the websocket handshakes work, set in the starting options:
+
+```erlang
+{ws_force_ssl, true}
+```
+
+If you are using stunnel to terminate, to make misultin expect a PROXY.. line as per the [proxy protocol](http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt) you can also set in the starting options:
+```erlang
+{proxy_protocol, true}
+```
+
+Newer versions of stunnel support this with the "protocol = proxy" config option.
View
250 README.txt
@@ -1,250 +0,0 @@
-======================================================================================
-MISULTIN - An Erlang library for building fast lightweight HTTP servers.
-<https://github.com/ostinelli/misultin>
-
->-|-|-(°>
-
-
-INSTALL INSTRUCTIONS
-======================================================================================
-
-1. Compile
-
-Run the appropriate script:
-
- * OSX | Linux users: make
- * Windows users: make.bat. Note that Erlang bin directory (by default,
- C:\Program Files\erl5.x.x\bin\) must be in your path for the script to work.
-
-This script will compile the .erl files in the Misultin src directory and save the
-compiled files into the ebin directory.
-
-2. (Optional) Copy Misultin files
-
-This optional step will allow Misultin to be called from modules running from any
-directory on your file system.
-
-Locate the directory where Erlang is installed on your system. Under OSX and Linux, it
-should be something similar to /usr/local/lib/erlang/ or /usr/lib/erlang/. Under
-Windows, Erlang is installed by default in something similar to
-C:\Program Files\erl5.7.2\ (version changes may apply).
-
-Browse into the lib directory under this Erlang root and copy the root misultin-0.x
-directory into this directory. You should now have Misultin under something similar
-to:
-
- * OSX | Linux users: /usr/local/lib/erlang/lib/misultin-0.x/
- * Windows users: C:\Program Files\erl5.7.2\lib\misultin-0.x\
-
-3. Test
-
-CD to the Misultin examples directory.
-
-If you did proceed with step 2, start an Erlang shell:
-$ erl
-
-If you did not proceed with step 2, start an Erlang shell specifying where the
-compiled .beam files are:
-$ erl -pa ../ebin
-
-In the shell, compile and run misultin_hello_world by issuing:
-
-(one@rob.loc)1>c(misultin_hello_world).
-{ok,misultin_hello_world}
-(one@rob.loc)2>misultin_hello_world:start(8080).
-{ok,<0.50.0>}
-
-Open your favourite browser and point it to http://localhost:8080/, you should read
-"Hello World." printed on your page.
-
-You may now stop the misultin_hello_world HTTP server:
-
-(one@rob.loc)3>misultin_hello_world:stop().
-
-4. Congratulations!
-
-You're ready to go.
-
->-|-|-(°>
-
-
-DOCUMENTATION
-======================================================================================
-
-API Documentation is available online on the Misultin's wiki:
-https://github.com/ostinelli/misultin/wiki
-
-
-SSL NOTES
-======================================================================================
-If you are running misultin behind an SSL terminator such as stunnel or stud, then set
- {ws_force_ssl, true}
-so that websocket handshakes work.
-
-If you are using stunnel to terminate, you can also set
- {proxy_protocol, true}
-to make misultin expect a PROXY.. line as per
-http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
-
-Newer versions of stunnel support this with the "protocol = proxy" config option.
-
-
-CHANGELOG
-======================================================================================
-
-0.9-dev:
- - added SESSIONS state, persistent across requests
- - added access log callback function, so that main application can log HTTP
- access
- - added streaming input for big files or endless input, using a manual
- body_recv function in conjunction with the {auto_recv_body, false} option
- - added static directory support, so that GET requests to /static/* can
- automatically send files from a specified directory [thanks to egobrain
- suggestion]
- - added request redirection helper method
- - consistently improved memory usage by not copying by default to handler
- processes the full request or websocket record
- - added configuration option to set which websocket versions must be
- supported by the server
- - added support for websocket draft-hybi-10
- - added support for websocket draft-hybi-17 (thanks to RJ)
- - added support for websockets on FireFox (thanks to Egobrain)
- - added support for 'If-Modified-Since' headers in file sending [thanks to
- davidgaleano]
- - added support for websockets when behind stunnel with
- {external_ssl, boolean()} option (thanks to RJ)
- - added support to see the correct client IP when behind stunnel, according
- to <http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt>
- [thanks to RJ]
- - added support for OPTIONS method [thanks to majek]
- - rebar-ized makefile
- - corrected minor bugs [thank you all - you know who you are!]
-
-0.8: - Misultin has been redesigned to use supervisor behaviours where
- appropriate, to be more OTP compliant
- - added Cookie support
- - added preliminary support multipart/form-data and a file upload example
- [thanks to Max Lapshin]
- - added Date and Server headers
- - added support for headers being specified as binaries [thanks to akaspin]
- - added an example on how to properly embed misultin in your application
- - Req:get(peer_addr) now properly extracts peer information from headers
- "X-Real-Ip" or "X-Forwarded-For" if these are available [thanks to Max
- Lapshin]
- - solved bug on large data being sent over via websockets [thanks to omarkj]
- - corrected binary sending bug in websockets which would fail binaries on
- io_lib format [thanks to normanb]
- - added recbuf advanced option [issue #40]
- - added preliminary test suite
- - various optimizations using binary when needed
-
-0.7.1: - considerably improved stability under heavy load
- - misultin now accepts incoming connections with a pool of acceptors
- instead of a single one
- - Misultin can now be used both with parametrized modules and with pure
- erlang code too [thanks to yrashk, nox and essen]
- - added support for HEAD, PUT, DELETE, TRACE and CONNECT methods
- - now websockets are on {active, once} mode to avoid malicious clients
- overflooding [thanks to essen]
- - ensured that body of request can be read on all methods except TRACE as
- per http specs
- - added support for iolist() in chunked resposes [thanks to RJ]
-
-0.7: - added max_connections options parameter, which specifies maximum
- concurrent open connections accepted by the server
- - added post_max_size options parameter, which sets the maximum size of POST
- data
- - added get_url_max_size options parameter, which sets the maximum length of
- URI
- - added CHUNKED support, both for incoming requests and outgoing responses
- [thanks to yrashk suggestion]
- - added trapping of client closing a browser in Comet applications [thanks
- to yrashk]
- - added SSL support for websockets [enhancement track #25, thanks to
- viplifes]
- - Misultin can now be started without a registered name or with a different
- name, so that multiple versions of misultin can be started on a single
- node
- - added support for IP address specified in tuple format [thanks to
- okeuday suggestion]
- - added support to extract plain uri unquoted as a list() [thanks to
- okeuday]
- - added Comet Long Polling example
- - added Comet iFrame example
- - added the killing of alive processes on server shutdown
- - the GET uri parameters are now also available on POST requests
- - added custom headers on file sending to browser [thanks to josevalim]
- - additional minor adjustments
-
-0.6.2: - refactored to considerably improve sending of static files
- - minor bug corrections
-
-0.6.1: - added support to websocket protocol hixie draft 76 [thanks to sergio
- veiga]
- - added support to multiple websocket draft protocols [for backwards
- compatibility]
- - added ws_autoexit option which allows to get an event on websocket
- controlling processes [issue track #15, suggestion of esente]
- - added headers also in misultin websockets [thanks to jlirochon]
- - made it basho's rebar friendly [thanks to mrinalwadhwa]
-
-0.6: - added HTTP compression option
- - refactoring of the main server loop, so that it is now isolated from the
- HTTP functionality
- - removed unnecessary compilation warnings
- - replaced proplists:get_value with much faster utility function
-
-0.5: - added SSL support
- - refactoring of the acceptor loop
-
-0.4: - added preliminary websocket support
-
-0.3.4: - added Req support to return the socket handling the request
- - bug correction on Content-Length: 0 header causing timeout on POST
- requests [issue track #12, thanks to gdamjan]
-
-0.3.3: - added echoing of the Connection header [issue track #7, thanks to
- thijsterlouw]
- - bug correction on acceptor respawning [issue track #10, thanks to
- thijsterlouw]
-
-0.3.2: - optimized error handling [issue track #5, thanks to Max Lapshin]
-
-0.3.1: - added flow control using inet options {active, once} [issue track #4,
- thanks to Max Lapshin]
- - added support to standard http headers response
- - added http 400 bad request error in socket handling
- - bug correction: removed erroneous sending of response timeout on listening
- open connections
- - added stream_support optimization option
-
-0.3: - reengineering of the listener process, using active instead of passive
- mode in request parsing, except for BODY where passive is still used
- [thanks to Lev Walkin]
- - added better support for request timeout
-
-0.2.2: - added .app file [thanks to Essien Ita Essien]
- - simplified get_options [thanks to Essien Ita Essien]
- - added ip address option [thanks to Essien Ita Essien]
- - added ipv6 support
- - added recv_timeout option
- - bug correction: requests peer address and port are now not reset on open
- connections multiple requests
-
-0.2.1: - added support for Content-Type that specifies charset in POST data
- [thanks to Tuncer Ayaz]
- - added support for iolist in misultin_req:ok/1,2 and
- misultin_req:respond/2,3
- - code optimized taking out unnecessary binary conversion and lists:flatten
- [thanks to Feng Yu]
-
-0.2: - added trap exit for acceptor failure
- - added backlog option
- - added fallback if no connection header is present [issue track #1, thanks
- to Ciconia]
- - added limit for parsing headers to avoid malicious attacks [thanks to
- Mazen Harake]
- - minor bug corrections
-
-0.1: - initial release.
-

0 comments on commit 59cc556

Please sign in to comment.