CGI/Comments

From J Wiki
< CGI
Jump to navigation Jump to search

This is discussion page for comments on the CGI framework.

See also Web/Comments for related General forum threads:

-- Oleg Kobchenko <<DateTime(2007-01-15T08:53:50Z)>> ----


Possible JHP change

Would the following change to the qkeys function in JHP be sensible? It seems to me it would enable the use of the qparam function for form data as well as query strings?

qkeys=: 3 : 0
  if. 0~:nc<'CGIKEYS' do.
   if. 'application/x-www-form-urlencoded'-: 2!:5 'CONTENT_TYPE' do.
     inpt=: stdin ''
   else.
     inpt=: 2!:5 'QUERY_STRING'
   end.
   'CGIKEYS CGIVALS'=: a:"_`(<"1@|:)@.(0<#) qsparse inpt
  end.
  CGIKEYS
)

-- Ric Sherlock <<DateTime(2007-03-27T22:12:03Z)>> ----

Cookies with JHP

I couldn't find any existing facility to add Cookies in JHP. After some research into how cookies are set etc, I came up with the two functions below that could be added to jhp.ijs.

In a JHP page they could be used like this.

<% SetCookie 'foo=bar;' %>
<% DeleteCookie 'oldfoo' %>
<% ContentType'text/html' %>
<html><head>...

The two functions are:

NB.*SetCookie v writes line to delete/expire a cookie
NB. y is string to set cookie
NB. e.g. SetCookie 'foo=bar;'
NB. e.g. SetCookie 'foo=bar; domain=domain.com; path=/; expires=Fri, 29-Mar-2007 13:46:00 GMT'
SetCookie=: 3 : 0
  if. 0 <: nc<'CookiesSet_j_' do.
    CookiesSet_j_=: CookiesSet_j_;y
  else.
    CookiesSet_j_=: y
  end.
 print 'Set-Cookie: ',":y
)

NB.*DeleteCookie v writes line to delete/expire a cookie
NB. y is string - name of cookie to delete
NB. e.g. DeleteCookie 'foo'
DeleteCookie=: 3 : 0
  ck=.y,'=;'
  expire=. ' expires=Thu, 01-Jan-1970 00:00:00 GMT;'
  SetCookie ck,expire
)

-- Ric Sherlock <<DateTime(2007-03-27T22:19:17Z)>> ----

stderr definition for Win32 in JHP?

Looking through jhp.ijs I see that stdin, stdout & stderr are defined at the start of the script for a Unix-based system. At the end of the script a check is done to see if the system is running Windows and if so overwrites the definitions of stdin & stdout with the Windows equivalents. My question is whether stderr should also be redefined.

It is set at the start of the script using 1!:2&5 which I understand from the documentation of Foreign conjunctions is Unix only. Should it be redefined at the end of the script something like this?

stderr_z_=: [: WriteFile_j_ (GetStdHandle_j_ _12) ; , ; # ; ,@2: ; 0:

To be honest I haven't worked out all of the things this sentence is doing, but am assuming it should be similar to stdout except for the different handle value.

I haven't noticed anything suggesting that this is currently a problem in JHP, just looked like an inconsistency.

-- Ric Sherlock <<DateTime(2007-03-29T02:32:47Z)>> ----

  • The stdout routine was redefined for Windows because the standard output behaves badly: instead of treating end of lines as is, it adds CR, which makes it impossible to output binary data like images that used in JHP. On the other hand stderr is actually supported for Windows too, and as I believe is written to the log file by the web server. It does not need the binary format, so it's OK to use 1!:2&5. -- Oleg Kobchenko <<DateTime(2007-03-29T06:19:24Z)>>

Parsing multipart/form-data in JHP

Here is a first draft of some changes to JHP that would enable it to parse forms & files uploaded using the multipart/form-data content type. It is very verbose and certainly not as elegant as the rest of JHP, but it seems to work so hopefully it can act as a starting point.

The qkeys verb has been extended. Four extra global nouns are defined for multipart/form-data (CGIISFL -boolean, is the key a file; CGIFNMS -for files, the filenames to write uploaded file data to; CGICTPS -for files, the content-type; CGIFDAT - for files, the file data).

qkeys=: 3 : 0
  if. -.isnoun 'CGIKEYS' do.
    select. env 'REQUEST_METHOD'
      case. 'GET'  do.
        q=. env 'QUERY_STRING'
        'CGIKEYS CGIVALS'=: a:"_`(<"1@|:)@.(0<#) qsparse q
      case. 'POST' do.
        q=. stdin ''
      select. (]{.~';'i.~]) env 'CONTENT_TYPE'
        case. 'application/x-www-form-urlencoded' do.
          'CGIKEYS CGIVALS'=: a:"_`(<"1@|:)@.(0<#) qsparse q
        case. 'multipart/form-data' do.
          NB. t=. q fwrite jpath '~CGI/tmp/temp.stdin'
          NB. dat=. qmparse q
          'CGIKEYS CGIVALS CGIISFL CGIFNMS CGICTPS CGIFDAT'=: a:"_`(<"1@|:)@.(0<#) qmparse q
        case. do.
    NB. signal invalid CONTENT_TYPE
      end.
    case. do.
  NB. signal invalid Method
    end.
  end.
  CGIKEYS
)

The following verb qmparse has been added to do the parsing work for this form of data.

qmparse=: 3 : 0
  (env 'CONTENT_TYPE') qmparse y
  :
  bd=.  x ([}.~[:>:i.) '='  NB. get boundary
  dat=. (#bd)}.each (bd E. y) <;.1 y NB. box each section

  ndx=. {.each I. each (<CRLF,CRLF) E. each dat NB. find header/body split
  dat=. (0&<@:>ndx)#dat     NB. drop out non-fields
  ndx=.  (0&<@:>ndx)# ndx
  dat=. ndx split each dat  NB. split header/body
  hdrs=. 0{::each dat
  dat=. 1{::each dat

  s=. 'name='
  ndx=. {.each I. each (<s) E. each hdrs NB. find string starts
  ndx=. (<#s) + each ndx                 NB. add string lengths
  keys=. ndx }.each hdrs                 NB. drop til after
  keys=. (*./\each -. each keys e. each <';',CR)# each keys  NB. drop everything from ; or CR
  keys=. keys-.each <'"'                 NB. remove "s

  s=. 'filename='
  ndx=. {.each I. each (<s) E. each hdrs
  isfile=. 0&<@:>ndx                 NB. is section a file?
  ndx=. (<#s) + each isfile#ndx
  fnmes=. ndx }. each isfile#hdrs
  fnmes=. (*./\each -. each fnmes e. each <';',CR)# each fnmes
  fnmes=. fnmes-.each <'"'

  s=. 'Content-Type: '
  ndx=. {.each I. each (<s) E. each isfile#hdrs
  ndx=. (<#s)+each ndx
  contypes=. ndx }. each isfile#hdrs
  contypes=. (*./\each -. each contypes e. each <';',CR)# each contypes
  contypes=. contypes-.each <'" '

  dat=. _4}.each 4}.each dat      NB. drop 2CRLFs at start and CRLF-- at end
  fdat=. isfile#dat

  dat=. fnmes (I.isfile) }dat     NB. for files replace value with filename
  isfull=. 0&<@:>#each fdat
  if. +./isfull do.               NB. create filenames for writing if data exists
    tp=. jpath '~CGI/tmp/'        NB. path for temp folder
    fnmes=. (<tp), each isfull#fnmes   NB. ***generate new unique mangled filenames here??
  end.
  fnmes=. isfile expand ,.fnmes
  contypes=. isfile expand ,.contypes
  fdat=. isfile expand ,.fdat
  keys,.dat,.(<@>isfile),.fnmes,.contypes,.fdat
)

-- Ric Sherlock <<DateTime(2007-05-29T17:01:22Z)>>