A server-side web framework written in Forth. http://www.1-9-9-1.com
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

207 Zeilen
6.5KB

  1. \ 1991
  2. include unix/socket.fs
  3. \ Helper words
  4. : +s ( addr1 u1 addr2 u2 -- addr3 u3 ) \ like s+ but prepend rather than append.
  5. 2swap s+ ;
  6. : exchange ( a1 a2 -- )
  7. 2dup c@ swap c@ rot c! swap c! ;
  8. : reverse ( caddr u -- ) \ reverse a string
  9. 1- bounds begin 2dup > while
  10. 2dup exchange
  11. -1 /string
  12. repeat 2drop ;
  13. : sourcedir ( -- saddr su )
  14. \ Returns the directory in which the file
  15. \ invoking the word finds itself
  16. \ relative to gforth's execution directory.
  17. \ Useful for specifying in which dir to find
  18. \ specific files (e.g., public/, views/).
  19. sourcefilename \ get the name of our file
  20. pad dup >r place \ copy the string so we don't
  21. r> count \ modify sourcefilename.
  22. 2dup reverse \ reverse and search for first /
  23. s" /" search if \ if found, reverse string to
  24. 2dup reverse \ strip the filename but keep dir.
  25. else
  26. 2drop \ no slash,
  27. s" ./" \ same dir execution.
  28. then ;
  29. \ User-defined routing
  30. wordlist constant routes
  31. : find-route ( addr u -- data )
  32. routes search-wordlist if
  33. >body @
  34. else 0 then ;
  35. : register-route ( data addr u -- )
  36. 2dup routes search-wordlist if
  37. routes drop nip nip
  38. >body !
  39. else
  40. routes get-current >r set-current \ switch definition word lists
  41. nextname create ,
  42. r> set-current
  43. then ;
  44. \ Public directory
  45. : pubvar create 0 , 0 , ;
  46. pubvar public
  47. : set-public-path ( addr u -- )
  48. public 2! ;
  49. : get-public-path ( -- addr u )
  50. public 2@ ;
  51. sourcedir s" public" s+ set-public-path
  52. \ Views directory
  53. pubvar views
  54. : set-view-path ( addr u -- )
  55. views 2! ;
  56. : get-view-path ( -- addr u )
  57. views 2@ ;
  58. sourcedir s" views" s+ set-view-path
  59. \ Query params
  60. pubvar queryString
  61. : set-query-string ( addr u -- )
  62. queryString 2! ;
  63. : get-query-string ( -- addr u )
  64. queryString 2@ ;
  65. \ Request's Content-Type
  66. pubvar RequestContentType
  67. : set-content-type ( addr u -- )
  68. RequestContentType 2! ;
  69. : get-content-type ( -- addr u )
  70. RequestContentType 2@ ;
  71. : filetype: ( addr u "extension" -- ) \ takes a content-type and the extension
  72. create here over 1+ allot place
  73. does> count ;
  74. : get-filetype ( addr u -- caddr cu ) \ takes an extension, looks to find a definition
  75. find-name dup if
  76. name>int
  77. execute
  78. else
  79. drop
  80. s" text/plain"
  81. then ;
  82. s" text/plain" filetype: txt \ txt should always be defined
  83. s" text/html" filetype: html
  84. s" text/css" filetype: css
  85. s" text/javascript" filetype: js
  86. s" image/png" filetype: png
  87. s" image/gif" filetype: gif
  88. s" image/jpeg" filetype: jpg
  89. s" image/jpeg" filetype: jpeg
  90. s" image/x-icon" filetype: ico
  91. \ Internal request handling
  92. : HTTP/1.1 s" HTTP/1.1 " ;
  93. : response-status ( u -- addr u )
  94. dup case \ get status code info
  95. 200 of s" OK" endof
  96. 404 of s" Not Found" endof
  97. endcase
  98. s\" \n" s+
  99. rot s>d <# #s #> +s \ convert status code to string and prepend to info
  100. HTTP/1.1 +s ; \ prepend HTTP/1.1
  101. : content-type ( addr u -- caddr cu )
  102. s" Content-Type: " +s \ Prepend to the provided content type
  103. s\" \n\n" s+ ; \ Append 2 new lines
  104. : set-header ( u addr u -- raddr ru ) \ Accepts status code and content type string
  105. rot response-status \ Set response status
  106. 2swap content-type \ Set content-type
  107. s+ ; \ Join
  108. : read-request ( socket -- addr u )
  109. pad 4096 read-socket ;
  110. : send-response ( addr u socket -- )
  111. dup >r write-socket r> close-socket ;
  112. : store-query-string ( addr u -- raddr ru )
  113. 2dup s" ?" search if
  114. 2dup set-query-string \ store query string
  115. swap drop -
  116. else
  117. s" " set-query-string \ store empty query string (reset)
  118. 2drop
  119. then ;
  120. : requested-route ( addr u -- raddr ru )
  121. bl scan 1- swap 1+ swap
  122. 2dup bl scan swap drop - \ get the space-separated route
  123. store-query-string ; \ strip and store the query, leave route
  124. : file-exists? ( addr u -- addr u bool )
  125. 2dup file-status nip 0= ;
  126. : .extension ( addr u -- addr u )
  127. 2dup reverse \ reverse the file name
  128. 2dup s" ." search \ search for the first occurance of "."
  129. if
  130. swap drop - \ remove the "." from the search results
  131. else
  132. s" txt"
  133. then
  134. 2dup reverse ; \ reverse reversed extension
  135. : serve-file-type ( addr u -- )
  136. .extension get-filetype set-content-type ;
  137. : serve-file ( addr u -- addr u )
  138. slurp-file ;
  139. : 404content-type txt ;
  140. : 404html s" 404";
  141. : either-resolve ( addr u -- resolveaddr resolveu )
  142. s" GET" search if
  143. s" html" get-filetype set-content-type \ reset the request's content-type
  144. requested-route
  145. 2dup find-route dup if
  146. >r 2drop r> \ keep xt, drop the route string
  147. execute \ execute the user's route handler
  148. else
  149. drop \ drop the null xt
  150. get-public-path +s \ see if route exists in public dir
  151. file-exists? if
  152. 2dup serve-file \ collect file contents
  153. 2swap serve-file-type \ set the file type
  154. else
  155. exit \ continue to 404
  156. then
  157. then
  158. 200 get-content-type set-header +s
  159. rdrop exit then ;
  160. : or-404 ( addr u -- 404addr 404u )
  161. 2drop
  162. 404 404content-type set-header 404html s+ ;
  163. : prepare-response ( addr u -- returnaddr returnu)
  164. either-resolve or-404 ;
  165. : start-server { server client }
  166. begin
  167. server 255 listen
  168. server accept-socket to client
  169. client read-request prepare-response client send-response
  170. again ;
  171. \ Userland
  172. : 1991: ( port -- )
  173. create-server 0 start-server ;
  174. : /1991 ( "<path> <word>" -- )
  175. bl word ' swap count register-route ;