Add to show the raw url after paste. This allows pasting through curl using command line like this: `curl -F "text=<helloworld.cs" -F showUrl=1 http://localhost:8080/post` Also refactoring the URI handler to somewhat sanitize it...? I don't know. I had to at least hard code the 'http URI scheme in my code.
pastebin/httpserver.scm
| 57 | 57 | (meta (@ (name "viewport") (content "width=device-width, initial-scale=1")))) | |
| 58 | 58 | (body ,@body))) | |
| 59 | 59 | ||
| 60 | - | (define (make-raw-link-pb-entry pb-id) | |
| 61 | - | `(a (@ (href ,(format #f "/raw/~a" pb-id))) "raw")) | |
| 60 | + | (define (post-handler request request-body pb-data-path) | |
| 61 | + | (if (eq? (request-method request) 'POST) | |
| 62 | + | (let* ((headers (request-headers request)) | |
| 63 | + | (content-type-all (assq-ref headers 'content-type)) | |
| 64 | + | (content-type (if content-type-all | |
| 65 | + | (car content-type-all) | |
| 66 | + | #f)) | |
| 67 | + | (boundary (if (eq? content-type 'multipart/form-data) | |
| 68 | + | (assq-ref (cdr content-type-all) 'boundary) | |
| 69 | + | #f)) | |
| 70 | + | (reqbody-string (utf8->string request-body)) | |
| 71 | + | (form-data (if boundary | |
| 72 | + | (read-multipart-form-data reqbody-string boundary) | |
| 73 | + | #f)) | |
| 74 | + | (new-pb-data (if form-data | |
| 75 | + | (call-with-dir-as-pb-data | |
| 76 | + | pb-data-path | |
| 77 | + | (lambda (pb-data) | |
| 78 | + | (pb-data-new-entry pb-data | |
| 79 | + | (assoc-ref form-data "text")))) | |
| 80 | + | #f))) | |
| 81 | + | ||
| 82 | + | ;; determine what to respond | |
| 83 | + | (if (and new-pb-data | |
| 84 | + | (assoc-ref form-data "showUrl")) | |
| 85 | + | ||
| 86 | + | ;; show url after paste | |
| 87 | + | (values (build-response | |
| 88 | + | #:code 200 | |
| 89 | + | #:headers '((content-type . (text/plain)))) | |
| 90 | + | (lambda (port) | |
| 91 | + | (let* ((hostp (assq-ref headers 'host))) | |
| 92 | + | (put-string | |
| 93 | + | port | |
| 94 | + | (uri->string | |
| 95 | + | (build-uri 'http | |
| 96 | + | #:host (car hostp) | |
| 97 | + | #:port (cdr hostp) | |
| 98 | + | #:path (format #f "/raw/~a\r\n" | |
| 99 | + | (pb-entry-id new-pb-data)))))))) | |
| 100 | + | ||
| 101 | + | ;; respond with 303 See Other | |
| 102 | + | (values (build-response | |
| 103 | + | #:code 303 | |
| 104 | + | #:headers `((location . ,(build-uri-reference #:path "/")))) | |
| 105 | + | (lambda (port) 1)))) | |
| 106 | + | ||
| 107 | + | ;; INVALID request: access /post without HTTP POST | |
| 108 | + | (values (build-response #:code 400) | |
| 109 | + | (lambda (port) 1)))) | |
| 62 | 110 | ||
| 63 | 111 | (define (make-pastebin-handler data-path) | |
| 64 | 112 | (lambda (request request-body) | |
| 65 | - | (if (eq? (request-method request) 'POST) | |
| 66 | - | (let* ((headers (request-headers request)) | |
| 67 | - | (content-type-all (assq-ref headers 'content-type)) | |
| 68 | - | (content-type (if content-type-all (car content-type-all) #f)) | |
| 69 | - | (boundary (if (eq? content-type 'multipart/form-data) | |
| 70 | - | (assq-ref (cdr content-type-all) 'boundary) #f)) | |
| 71 | - | (reqbody-string (utf8->string request-body))) | |
| 72 | - | (if boundary | |
| 73 | - | (let ((form-data (read-multipart-form-data reqbody-string boundary))) | |
| 74 | - | (call-with-dir-as-pb-data | |
| 75 | - | data-path | |
| 76 | - | (lambda (pb-data) | |
| 77 | - | (pb-data-new-entry pb-data | |
| 78 | - | (assoc-ref form-data "text")))))))) | |
| 79 | - | ||
| 80 | - | ;; match raw file | |
| 81 | 113 | (match (split-and-decode-uri-path (uri-path (request-uri request))) | |
| 114 | + | ||
| 115 | + | ;; URI: /post -- create paste | |
| 116 | + | (("post" . _) | |
| 117 | + | (post-handler request request-body data-path)) | |
| 118 | + | ||
| 119 | + | ;; URI: /raw/<id> -- return raw content of the paste | |
| 82 | 120 | (("raw" pb-id) | |
| 83 | 121 | (values (build-response | |
| 84 | 122 | #:code 200 | |
| 85 | - | #:headers `((content-type . (text/plain)))) | |
| 123 | + | #:headers '((content-type . (text/plain)))) | |
| 86 | 124 | ||
| 87 | 125 | (lambda (port) | |
| 88 | 126 | (call-with-input-file | |
| 89 | 127 | ;; the file name | |
| 90 | - | (call-with-dir-as-pb-data data-path | |
| 91 | - | (lambda (p) (pb-get-file-path p pb-id))) | |
| 128 | + | (call-with-dir-as-pb-data | |
| 129 | + | data-path | |
| 130 | + | (lambda (p) (pb-get-file-path p pb-id))) | |
| 131 | + | ||
| 92 | 132 | ;; the input port | |
| 93 | 133 | (lambda (inport) | |
| 94 | 134 | (let A ((inport' inport)) | |
… | |||
| 98 | 138 | (put-bytevector port bv) | |
| 99 | 139 | (A inport')))))))))) | |
| 100 | 140 | ||
| 101 | - | ;; match everything else | |
| 141 | + | ;; URI: * -- everything else -- show the top 5 paste list | |
| 102 | 142 | (_ | |
| 103 | - | ||
| 104 | 143 | (values (build-response | |
| 105 | 144 | #:code 200 | |
| 106 | - | #:headers `((content-type . (text/html)))) | |
| 145 | + | #:headers '((content-type . (text/html)))) | |
| 107 | 146 | ||
| 108 | 147 | (lambda (port) | |
| 109 | 148 | (let* ((top5 (call-with-dir-as-pb-data | |
… | |||
| 111 | 150 | (lambda (pb-data) (pb-data-get-top pb-data 5)))) | |
| 112 | 151 | (sxml (templatize | |
| 113 | 152 | "pastebin" | |
| 114 | - | `((form (@ (method "post") (enctype "multipart/form-data")) | |
| 115 | - | (textarea (@ (name "text")) "") (input (@ (type "submit")))) | |
| 153 | + | `((form (@ (method "post") (enctype "multipart/form-data") | |
| 154 | + | (action "/post")) | |
| 155 | + | (textarea (@ (name "text")) "") | |
| 156 | + | (input (@ (type "checkbox") (name "showUrl") | |
| 157 | + | (id "showUrl") (value "1"))) | |
| 158 | + | (label (@ (for "showUrl")) "Show raw URL after paste") | |
| 159 | + | (input (@ (type "submit")))) | |
| 116 | 160 | (table (@ (border 1)) (tr (th "id") (th "text") (th "")) | |
| 117 | 161 | ,(map (lambda (entry) | |
| 118 | 162 | `(tr (td ,(pb-entry-id entry)) | |
| 119 | 163 | (td ,(pb-entry-text entry)) | |
| 120 | - | (td ,(make-raw-link-pb-entry (pb-entry-id entry))))) | |
| 164 | + | (td | |
| 165 | + | (a (@ (href | |
| 166 | + | ,(format #f "/raw/~a" | |
| 167 | + | (pb-entry-id entry)))) | |
| 168 | + | "raw")))) | |
| 121 | 169 | top5)))))) | |
| 122 | 170 | (display "<!DOCTYPE html>\n" port) | |
| 123 | 171 | (sxml->xml sxml port)))))))) | |