Browse Source

Add basic CRUD support.

TODO:
+ Make content-type available.
+ Make sure multipart/form-data works (not sure?).
+ Clean up recent code additions.
1991
urlysses 7 years ago
parent
commit
d775fd9ae6
3 changed files with 154 additions and 4 deletions
  1. +83
    -3
      1991.fs
  2. +1
    -1
      README.md
  3. +70
    -0
      examples/public/crud.html

+ 83
- 3
1991.fs View File

@@ -11,6 +11,10 @@ include unix/socket.fs
while 2over nip /string
r> 1+ >r
repeat 2drop 2drop r> ;
: -leading ( addr len -- addr' len' )
begin over c@ bl = while 1 /string repeat ;
: trim ( addr len -- addr' len')
-leading -trailing ;
: exchange ( a1 a2 -- )
2dup c@ swap c@ rot c! swap c! ;
: reverse ( caddr u -- ) \ reverse a string
@@ -65,6 +69,20 @@ pubvar tmpQueryString
+s \ adding our new query values.
set-tmp-query-string ;

\ Request body
pubvar requestBody
: set-request-body ( addr u -- )
requestBody 2! ;
: get-request-body ( -- addr u )
requestBody 2@ ;

\ Request method
pubvar requestMethod
: set-request-method ( addr u -- )
requestMethod 2! ;
: get-request-method ( -- addr u )
requestMethod 2@ ;

\ User-defined routing
wordlist constant routes
pubvar reqroute
@@ -317,8 +335,35 @@ s" image/x-icon" filetype: ico
2swap content-type \ Set content-type
s+ ; \ Join

: get-content-length ( addr u -- clen )
s" Content-Length:" search if
2dup s\" \n" search drop nip -
s" Content-Length:" nip /string
trim
s>number?
2drop
else
2drop
0
then ;

: read-request-body ( socket u -- )
\ Takes the socket and the length of the
\ body (Content-Length).
here swap aligned read-socket
set-request-body ;
: read-request ( socket -- addr u )
pad 4096 read-socket ;
\ Returns the request header
\ but also collects the request body.
dup >r
pad 4096 read-socket
r> dup 2over rot drop
get-content-length ?dup if
read-request-body
else
s" " set-request-body
drop
then ;

: send-response ( addr u socket -- )
dup >r write-socket r> close-socket ;
@@ -356,8 +401,42 @@ s" image/x-icon" filetype: ico
: 404content-type txt ;
: 404html s" 404" ;

: valid-method? ( addr u -- addr' u' bool )
2dup s" GET" search if
2nip
-1
s" GET" set-request-method
exit
then
2drop

2dup s" POST" search if
2nip
-1
s" POST" set-request-method
exit
then
2drop

2dup s" PUT" search if
2nip
-1
s" PUT" set-request-method
exit
then
2drop

2dup s" DELETE" search if
2nip
-1
s" DELETE" set-request-method
exit
then
2drop
0 ;

: either-resolve ( addr u -- resolveaddr resolveu )
s" GET" search if
valid-method? if
s" html" get-filetype set-content-type \ reset the request's content-type
requested-route
2dup find-route dup if
@@ -374,7 +453,8 @@ s" image/x-icon" filetype: ico
then
then
200 get-content-type set-header +s
rdrop exit then ;
rdrop exit
then ;

: or-404 ( addr u -- 404addr 404u )
2drop


+ 1
- 1
README.md View File

@@ -8,6 +8,6 @@ A server-side web framework written in Forth.
+ [x] file-serving if no user-defined routes match. Search "public/" dir
unless otherwise specified by user.
+ [x] query arguments
+ [ ] PUT, POST, DELETE
+ [x] PUT, POST, DELETE
+ [x] templating
+ [x] fuzzy-/pattern-match-enabled user routes (e.g., /something/*/wildcard)?

+ 70
- 0
examples/public/crud.html View File

@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>GET, PUT, POST, DELETE</title>
</head>
<body>
<input type="submit" value="GET" id="get">
<input type="submit" value="POST" id="post">
<input type="submit" value="PUT" id="put">
<input type="submit" value="DELETE" id="delete">
<script type="text/javascript">
// https://gist.github.com/EtienneR/2f3ab345df502bd3d13e
(function () {
function onload () {
var rt = xhr.responseText;
console.log(rt, xhr.readyState, xhr.status);
}
var url = "/api/v1/users";
var xhr = new XMLHttpRequest();
var get = document.querySelector("#get");
var post = document.querySelector("#post");
var put = document.querySelector("#put");
var del = document.querySelector("#delete");

// GET
get.onclick = function () {
xhr.open("GET", url + "/1", true);
xhr.onload = onload;
xhr.send(null);
};

// POST
// TODO: 201 status
post.onclick = function () {
var data = {};
data.firstname = "Aaaa";
data.lastname = "Bbbb";
var json = JSON.stringify(data);
xhr = new XMLHttpRequest();
xhr.open("POST", url + "/1", true);
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
xhr.onload = onload;
xhr.send(json);
};

// PUT
put.onclick = function () {
var data = {};
data.firstname = "Aaaa2";
data.lastname = "Bbbb2";
var json = JSON.stringify(data);
xhr = new XMLHttpRequest();
xhr.open("PUT", url + "/2", true);
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
xhr.onload = onload;
xhr.send(json);
};

// DELETE
del.onclick = function () {
xhr = new XMLHttpRequest();
xhr.open("DELETE", url + "/2", true);
xhr.onload = onload;
xhr.send(null);
};
}());
</script>
</body>
</html>

Loading…
Cancel
Save