core

This module is the foundation of Smisk and is implemented in machine native code.

See C API for documentation of the C interface.

Requires:libfcgi

Attributes

smisk.core.__build__

Build identifier in URN form, distinguishing each unique build.

See:smisk.release.build for more information about this attribute.

Changed in version 1.1.0: Prior to version 1.1.0, this was a abritrary (per-build unique) string. In 1.1.0 this is now a URN.

smisk.core.app

Current Application (None if no application has been created).

This is actually a smisk.util.objectproxy.ObjectProxy, inducing a slight performance hit, since accessing the actual application causes intermediate calls. Application.current is the most performance-effective way to access the current application. However, in most cases the performance hit induced by the ObjectProxy is so small, the increased readability and usage of app is preferred.

Example:

>>> import smisk
>>> smisk.app
None
>>> import smisk.core
>>> smisk.core.Application()
<smisk.core.Application object at 0x6a5c0>
>>> smisk.app
<smisk.core.Application object at 0x6a5c0>
See:Application.current

New in version 1.1.0.

smisk.core.request

Current Request (None if no application is running).

This is actually a smisk.util.objectproxy.ObjectProxy, inducing a slight performance hit, since accessing the actual application causes intermediate calls. Application.current.request is the most performance-effective way to access the current request. However, in most cases the performance hit induced by the ObjectProxy is so small, the increased readability of request is preferred.

See:Application.request

New in version 1.1.0.

smisk.core.response

Current Response (None if no application is running).

This is actually a smisk.util.objectproxy.ObjectProxy, inducing a slight performance hit, since accessing the actual application causes intermediate calls. Application.current.response is the most performance-effective way to access the current response. However, in most cases the performance hit induced by the ObjectProxy is so small, the increased readability of response is preferred.

See:Application.response

New in version 1.1.0.

Functions

smisk.core.bind(path[, backlog=-1])

Bind to a specific unix socket or host (and/or port).

Parameters:
  • path (string) – The Unix domain socket (named pipe for WinNT), hostname, hostname and port or just a colon followed by a port number. e.g. "/tmp/fastcgi/mysocket", "some.host:5000", ":5000", "\*:5000".
  • backlog (int) – The listen queue depth used in the :func:’listen()’ call. Set to negative or zero to let the system decide (recommended).
Raises:

smisk.IOError If already bound.

Raises:

IOError If socket creation fails.

See:

unbind(), listening()

smisk.core.unbind()

Unbind from a previous call to bind().

If not bound, calling this function has no effect. You can test wherethere or not the current process is bound by calling listening().

Raises:IOError on failure.

New in version 1.1.0.

smisk.core.listening()

Find out if this process is a “remote” process, bound to a socket by means of calling bind(). If it is listening, this function returns the address and port or the UNIX socket path.

See also: unbind()

Raises:smisk.IOError On failure.
Returns:Bound path/address or None if not bound.
smisk.core.uid(nbits[, node=None]) → string

Generate a universally Unique Identifier.

See documentation of pack() for an overview of :func:nbits.

The UID is calculated like this:

sha1 ( time.secs, time.usecs, pid, random[, node] )
Note:

This is not a UUID (ISO/IEC 11578:1996) implementation. However it uses an algorithm very similar to UUID v5 (RFC 4122). Most notably, the format of the output is more compact than that of UUID v5.

Parameters:
  • nbits (int) – Number of bits to pack into each byte when creating the string representation. A value in the range 4-6 or 0 in which case 20 raw bytes are returned. Defaults is 5.
  • node (string) – Optional data to be used when creating the uid.

New in version 1.1.0.

smisk.core.pack(data[, nbits=5]) → string

Pack arbitrary bytes into a printable ASCII string.

Overview of nbits:

0 bits, No packing:
20 bytes "0x00-0xff"
4 bits, Base 16:
40 bytes "0-9a-f"
5 bits, Base 32:
32 bytes "0-9a-v"
6 bits, Base 64:
27 bytes "0-9a-zA-Z,-"
Parameters:
  • data (string) –
  • nbits (int) – Number of bits to pack into each byte when creating the string representation. A value in the range 4-6.
See:

uid()

New in version 1.1.0.

smisk.core.object_hash(object) → long

Calculate a hash from any python object.

New in version 1.1.0.

Classes

class smisk.core.Application

An application.

Simple example:

from smisk.core import Application
class MyApp(Application):
  def service(self):
    self.response.write('<h1>Hello World!</h1>')

MyApp().run()

Example of standalone/listening/slave process:

from smisk.core import Application, bind
class MyApp(Application):
  def service(self):
    self.response.write('<h1>Hello World!</h1>')

bind('hostname:1234')
MyApp().run()

It is also possible to use your own types to represent Requests and Responses. You set request_class and/or response_class to a type, before application_will_start() has been called. For example:

from smisk.core import Application, Request
class MyRequest(Request):
  def from_internet_explorer(self):
    return self.env.get('HTTP_USER_AGENT','').find('MSIE') != -1

class MyApp(Application):
  def __init__(self):
    super(MyApp, self).__init__()
    self.request_class = MyRequest

  def service(self):
    if self.request.from_internet_explorer():
      self.response.write('<h1>Good bye, cruel World!</h1>')
    else:
      self.response.write('<h1>Hello World!</h1>')

MyApp().run()
current

Current application instance, if any. Class attribute.

See:smisk.core.app
forks

Number of child processes to fork off into.

This must be set before calling run(), as it’s in run() where the forking goes down. Defaults to 0 (disabled).

New in version 1.1.0.

request_class
Must be set before calling run()
response_class
Must be set before calling run()
sessions_class
Must be set before calling run() and should be an object implementing the smisk.session.Store interface.
request
The Request object.
response
The Response object.
sessions
An object with the smisk.session.Store interface.
show_traceback
If True, traceback information is included with error responses. Note that traceback information is always included in logs. Defaults to True.
application_did_stop()

Called when the application stops accepting incoming requests.

The default implementation does nothing.

application_will_start()

Called just before the application starts accepting incoming requests.

The default implementation does nothing.

error(typ, val, tb)

Handle an error and produce an appropriate response.

The built-in implementation renders error information as XHTML encoded in UTF-8 with the HTTP status code 500 (Internal Server Error).

You might override this to display a custom error response, but it is recommended you use this implementation, or at least filter certain higher level exceptions and let the lower ones through to this handler.

Normally, this is what you do:

class MyApp(Application):
  def error(self, typ, val, tb):
   if isinstance(val, MyExceptionType):
    self.nice_error_response(typ, val)
   else:
    Application.error(self, typ, val, tb)

What is sent as response depends on if output has started or not: If output has started, if has_begun is True, calling this method will insert a HTML formatted error message at the end of what has already been sent. If output has not yet begun, any headers set will be discarded and a complete HTTP response will be sent, including the same HTML message described earlier.

If show_traceback evaluates to true, the error message will also include a somewhat detailed backtrace. You should disable show_traceback in production environments.

Parameters:
  • typ – Exception type
  • val – Exception value
  • tb – Traceback
exit()
Exit application.
run()
Run application.
service()
Service a request.
class smisk.core.Request

A HTTP request

input

Input stream.

If you send any data which is neither x-www-form-urlencoded nor multipart format, you will be able to read the raw POST body from this stream.

You could read x-www-form-urlencoded or multipart POST requests in raw format, but you have to read from this stream before calling any of post or files, since they will otherwise trigger the built-in parser and read all data from the stream.

Example, parsing a JSON request:

from smisk.core import *
from smisk.serialization.json import json_decode
class App(Application):
  def service(self):
    if request.env['REQUEST_METHOD'] == 'POST':
      response('Input: ', repr(json_decode(self.request.input.read())), "\n")

App().run()

You could then send a request using curl for example:

curl --data-binary '{"Url": "http://www.example.com/image/481989943", "Position": [125, "100"]}' http://localhost:8080/
Type:Stream
error
Type:Stream
env

HTTP transaction environment.

Type:dict
url

Reconstructed URL

For example; if you need to know if running under SSL:

if request.url.scheme == 'https':
  response('Secure connection')
else:
  response('Big brother is watching you')
Type:URL
get

Parameters passed in the query string part of the URL

Type:dict
post

Parameters passed in the body of a POST request

Type:dict
files

Any files uploaded via a POST request

Type:dict
cookies

Any cookies that was attached to the request

Type:dict
session

Current session.

Any modifications to the session must be done before output has begun, as it will add a Set-Cookie: header to the response.

Type:object
session_id

Current session id

Type:str
is_active

Indicates if the request is active, if we are in the middle of a HTTP transaction

Type:bool
referring_url

New in version 1.1.0.

Type:URL
method

New in version 1.1.1.

HTTP method (“GET”, “POST”, etc.).

See:RFC 2616, HTTP 1.1, Method Definitions
Type:str
max_multipart_size

New in version 1.1.2.

Limits the amount of data which Smisk normally automatically parses received in a POST or PUT request. For example uploaded files.

Only applies to payloads with a mime-type matching multipart/* – if the payload is defined as another media type, is form data or does not specify a content type – Smisk will not touch the input thus no limits apply (it’s up to the code which eventually read the input to set limits).

Setting the value to -1 or lower disables the limit. Note that this is different from max_formdata_size (which can no be disabled).

Setting the value to 0 (zero) disables automatic multipart parsing (any multipart input will be left intact/unread).

Type:long
Default:2147483648 (2 GB)
See:max_formdata_size.
max_formdata_size

New in version 1.1.2.

Limits the amount of data which Smisk will accept in a */x-www-form-urlencoded payload.

Setting the value to 0 (zero) disables automatic form data parsing (any form data input will be left intact/unread).

Note that – in contrast to max_multipart_size – this limit can not be disabled, only adjusted.

Type:long
Default:10737418 (10 MB)
See:max_multipart_size
log_error(message)

Log something through error including process name and id.

Normally, error ends up in the host server error log.

class smisk.core.Response

A HTTP response.

headers

Response headers.

Type:list
out

Output stream.

Type:Stream
has_begun

Indicates if the response has begun.

Check if output (http headers & possible body) has been sent to the client.

Read-only.

True if begin() has been called and output has started, otherwise False.

Type:bool
__call__(*strings)

Respond with a series of byte strings.

This is equivalent of calling writelines(strings), thus if begin() has not yet been called, it will be. Calling without any arguments has no effect. Note that the arguments must be strings, as this method actually uses writelines.

send_file(path)

Send a file to the client by using the host server sendfile-header technique.

Parameters:
  • path (string) – If this is a relative path, the host server defines the behaviour.
Raises EnvironmentError:
 

If smisk does not know how to perform sendfile through the current host server or if response has already started.

Raises IOError:
begin()

Begin response - send headers.

Automatically called by mechanisms like write() and Application.run().

Raises EnvironmentError:
 if response has already started.
write(str)

Write str bytes to out output stream.

begin() will be called if response has not yet begun.

Parameters:
  • string (str) – Data.
Raises IOError:
writelines(lines)

Write a sequence of byte strings to the output stream.

The sequence lines can be any iterable object producing strings, typically a list or tuple of strings. There is no return value. (This interface matches that of the Python file object readlines() and writelines())

Does not add line separators or modify the strings in any way.

This method esentially calls begin() if not has_begun, then calls out.writelines(lines). The difference between calling writelines() (this method) and out.writelines() (Stream.writelines()) is that the latter will not call begin() if needed. You should always use this method instead of out.writelines(), unless you are certain begin() has been called. (begin() is automatically called upon after a service() call if it has not been called, so you can not count on it not being called at all.)

Parameters:
  • lines (iterable) – A sequence of byte strings
Raises IOError:
find_header(name) → int

Find a header in the list of :attr:’headers’ matching prefix in a case-insensitive manner.

Parameters:
  • name (str) – Name or prefix of a header. i.e. “Content-type:” or “Content”.
Returns:

Index in :attr:’headers’ or -1 if not found.

Set a cookie.

Setting a cookie effectively appends a header to headers. The cookie set will not be made available in Request.cookies.

Parameters:
  • name (string) – The name of the state information (cookie). names that begin with $ are reserved for other uses and must not be used by applications.
  • value (string) – Opaque to the user agent and may be anything the origin server chooses to send, possibly in a server-selected printable ASCII encoding. Opaque implies that the content is of interest and relevance only to the origin server. The content may, in fact, be readable by anyone that examines the Set-Cookie header.
  • comment (string) – Optional. Because cookies can contain private information about a user, the Cookie attribute allows an origin server to document its intended use of a cookie. The user can inspect the information to decide whether to initiate or continue a session with this cookie.
  • domain (string) – Optional. The Domain attribute specifies the domain for which the cookie is valid. An explicitly specified domain must always start with a dot.
  • path (string) – Optional. The Path attribute specifies the subset of URLs to which this cookie applies.
  • secure (bool) – Optional. The Secure attribute directs the user agent to use only (unspecified) secure means to contact the origin server whenever it sends back this cookie. The user agent (possibly under the user’s control) may determine what level of security it considers appropriate for secure cookies. The Secure attribute should be considered security advice from the server to the user agent, indicating that it is in the session’s interest to protect the cookie contents.
  • version (int) – Optional. The Version attribute, a decimal integer, identifies to which version of the state management specification the cookie conforms. For the RFC 2109 specification, Version=1 applies. If not specified, this will be set to 1.
  • max_age (int) – The value of the Max-Age attribute is delta-seconds, the lifetime of the cookie in seconds, a decimal non-negative integer. To handle cached cookies correctly, a client should calculate the age of the cookie according to the age calculation rules in the HTTP/1.1 specification. When the age is greater than delta-seconds seconds, the client should discard the cookie. A value of zero means the cookie should be discarded immediately (not when the browsers closes, but really immediately)
  • http_only (bool) – When True the cookie will be made accessible only through the HTTP protocol. This means that the cookie won’t be accessible by scripting languages, such as JavaScript. This setting can effectly help to reduce identity theft through XSS attacks (although it is not supported by all browsers).

Note

Setting a cookie will cause the response not to be cached by proxies or peer browsers.

See also

RFC 2109 - HTTP State Management Mechanism

class smisk.core.Stream

A file-like I/O stream connected to the host server.

TODO

class smisk.core.SessionStore(object)

Basic session store type

ttl

For how long a session should be valid, expressed in seconds.

Defaults to 900.

Type:int
name

Name used to identify the session id cookie.

Defaults to "SID".

Type:string
class smisk.core.FileSessionStore(SessionStore)

Basic session store which uses files

See:SessionStore
file_prefix

A string to prepend to each file stored in dir.

Defaults to tempfile.tempdir + "smisk-sess." – for example: /tmp/smisk-sess.

Type:string
gc_probability

New in version 1.1.0.

A value between 0 and 1 which defines the probability that sessions are garbage collected.

Garbage collection is only triggered when trying to read a session object, so this only effects requests which involves reading sessions.

Defaults to 0.1 (10% probability)

Type:float
read(session_id) → data
Parameters:
  • session_id (string) – Session ID
Raises:

InvalidSessionError if there is no actual session associated with session_id.

Return type:

object

write(session_id, data)
Parameters:
  • session_id (string) – Session ID
  • data (object) – Data to be associated with session_id
refresh(session_id)
TODO
destroy(session_id)
TODO
path(session_id) → string
Path to file for session_id.
class smisk.core.URL

Uniform Resource Locator

scheme

The URL schema, always in lower case.

Type:string
user
Type:string
password
Type:string
host
Type:string
port

Port number. 0 (zero) if unknown or not set.

Type:int
path
Type:string
query
Type:string
fragment
Type:string
__init__(obj) → URL

Initialize a new URL from obj.

If obj is a subclass of URL, a shallow copy of obj will be returned. If obj is something else, it will be converted (if needed) into a str and parsed as it would represent a URL. (i.e. "protocol://authority:port/path...")

to_s(scheme=True, user=True, password=True, host=True, port=True, port80=True, path=True, query=True, fragment=True) → str

String representation.

By passing False (or 0 (zero)) for any of the arguments, you can omit certain parts from being included in the string produced. This can come in handy when for example you want to sanitize away password or maybe not include any path, query or fragment.

If a string is passed for one of the keyword arguments, that string is used instead of the value stored inside the URL object:

>>> from smisk.core import URL
>>> URL('http://host.name:1234/some/path').to_s()
'http://host.name:1234/some/path'
>>> URL('http://host.name:1234/some/path').to_s(host='another.host')
'http://another.host:1234/some/path'

In some cases, you may not want to include certain port numbers (80 and 443 in most cases):

>>> from smisk.core import URL
>>> url = URL('https://host:443/some/path')
>>> url.to_s(port=url.port not in (80,443))
'https://host/some/path'
Return type:str
Aliases:to_str, __str__
static encode(s) → basestring

Encode any unsafe or reserved characters in a given string for use in URI and URL contexts.

The difference between encode and escape is that this function encodes characters like / and : which are considered safe for rendering url’s, but not for using as a component in path, query or the fragment.

In other words: Use encode() for path, query and fragment components. Use escape() on whole URLs for safe rendering in other contexts.

Characters being escaped: $ &+,/;=?<>"#%{}|\^~[]`@: Also low and high characters (< 33 || > 126) are encoded.

Parameters:
  • s (basestring) –
Raises TypeError:
 

if s is not a str or unicode

static escape(s) → basestring

Escape unsafe characters <> "#%{}|\^~[]`@:\033 in a given string for use in URI and URL contexts.

See documentation of encode() to find out about the differences.

Parameters:
  • s (basestring) –
Raises TypeError:
 

if s is not a str or unicode

static decode(s) → basestring

Restore data previously encoded by encode() or escape().

Done by transforming the sequences %HH to the character represented by the hexadecimal digits HH.

Parameters:
  • str (basestring) –
Raises TypeError:
 

if s is not a str or unicode

Aliases:

unescape

static decompose_query(string, charset='utf-8') → str

Parses a query string into a dictionary.

>>> from smisk.core import URL
>>> print URL.decompose_query('name=Jack%20%C3%B6l&age=53')
{'age': u'53', 'name': u'Jack \xc3\xb6l'}
Parameters:
  • charset (str) – Character encoding of s used to create unicode values and normalized str keys. If charset is None, a str (bytes) is returned instead of a unicode.

Exceptions

exception smisk.core.Error
exception smisk.core.IOError
exception smisk.core.InvalidSessionError

Modules