logo

class

wisp::WispRes

sys::Obj
  web::WebRes
    wisp::WispRes
   1  //
   2  // Copyright (c) 2007, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //   27 Jun 07  Brian Frank  Creation
   7  //
   8  
   9  using web
  10  
  11  **
  12  ** WispRes
  13  **
  14  class WispRes : WebRes
  15  {
  16  
  17  //////////////////////////////////////////////////////////////////////////
  18  // Construction
  19  //////////////////////////////////////////////////////////////////////////
  20  
  21    new make(WispService service, OutStream o)
  22    {
  23      this.service = service
  24      @out = WebOutStream.make(o)
  25      headers.caseInsensitive = true
  26    }
  27  
  28  //////////////////////////////////////////////////////////////////////////
  29  // WebRes
  30  //////////////////////////////////////////////////////////////////////////
  31  
  32    **
  33    ** WispService.
  34    **
  35    override WispService service
  36  
  37    **
  38    ** Get or set the HTTP status code for this response. Status code
  39    ** defaults to 200. If response has already been committed, throws Err.
  40    ** If status code passed in is not recognized, throws Err.
  41    **
  42    override Int statusCode := 200
  43    {
  44      set
  45      {
  46        checkUncommitted
  47        if (statusMsg[val] == null) throw Err.make("Unknown status code: $val")
  48        @statusCode = val
  49      }
  50    }
  51  
  52    **
  53    ** Map of HTTP response headers.  You must set all headers before
  54    ** you access out() for the first time, which commits the response.
  55    ** After the response is commited this map becomes read only.
  56    **
  57    override Str:Str headers := Str:Str[:]
  58  
  59    **
  60    ** Return true if this response has been commmited.  A committed
  61    ** response has written its response headers, and can no longer
  62    ** modify its status code or headers.  A response is committed the
  63    ** first time that `out` is called.
  64    **
  65    override readonly Bool isCommitted := false
  66  
  67    **
  68    ** Return the WebOutStream for this response.  The first time this
  69    ** method is accessed the response is committed: all headers
  70    ** currently set will be written to the stream, and can no longer
  71    ** be modified.
  72    **
  73    override WebOutStream out
  74    {
  75      get
  76      {
  77        commit
  78        return @out
  79      }
  80    }
  81  
  82    **
  83    ** Send a redirect response to the client using the specified status
  84    ** code and url.  If this response has already been committed this
  85    ** method throws an Err.
  86    **
  87    override Void redirect(Int statusCode, Uri uri)
  88    {
  89      checkUncommitted
  90      this.statusCode = statusCode
  91      headers["Location"] = uri.toStr
  92      headers["Content-Length"] = "0"
  93      commit
  94    }
  95  
  96    **
  97    ** Send an error response to client using the specified status and
  98    ** HTML formatted message.  If this response has already been committed
  99    ** this method throws an Err.  If the server has a preconfigured page
 100    ** for this error code, it will trump the message passed in.
 101    **
 102    override Void sendError(Int statusCode, Str msg := null)
 103    {
 104      checkUncommitted
 105      this.statusCode = statusCode
 106      headers["Content-Type"] = "text/html"
 107  
 108      out.docType
 109      out.html
 110      out.head.title("$statusCode ${statusMsg[statusCode]}").headEnd
 111      out.body
 112      out.h1(statusMsg[statusCode])
 113      if (msg != null) out.w(msg).nl
 114      out.bodyEnd
 115      out.htmlEnd
 116    }
 117  
 118  //////////////////////////////////////////////////////////////////////////
 119  // Impl
 120  //////////////////////////////////////////////////////////////////////////
 121  
 122    **
 123    ** If the response has already been committed, then throw an Err.
 124    **
 125    Void checkUncommitted()
 126    {
 127      if (isCommitted) throw Err.make("WebRes already committed")
 128    }
 129  
 130    **
 131    ** If we haven't committed yet, then write the response header.
 132    **
 133    Void commit()
 134    {
 135      if (isCommitted) return
 136      isCommitted = true
 137      headers = headers.ro
 138      @out.w("HTTP/1.1 ").w(statusCode).w(" ").w(statusMsg[statusCode]).w("\r\n")
 139      headers.each |Str v, Str k| { @out.w(k).w(": ").w(v).w("\r\n") }
 140      @out.w("\r\n")
 141    }
 142  
 143  }