A server-side web framework written in Forth. http://www.1-9-9-1.com
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

205 строки
6.3KB

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