-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrequest.rkt
153 lines (133 loc) · 5.2 KB
/
request.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#lang racket
(require "gopher.rkt")
(provide url->request
request->url
dir-entity->request
gopher-url-request?
gopher-url-request->url
(struct-out request))
(struct request
(protocol ; symbol
host ; string
port ; port-number?
path/selector ; string
type) ; character
#:prefab)
(define (dir-entity->request dir-entity)
(request 'gopher
(gopher-dir-entity-host dir-entity)
(string->number (gopher-dir-entity-port dir-entity))
(gopher-dir-entity-selector dir-entity)
(gopher-dir-entity-type dir-entity)))
;; (regexp-match #px"^(\\w+://)?([a-zA-Z0-9\\.]+)(:\\d+)?(/.*)?" "gopher://abc6.def.com:70/a/b/c.txt")
(define (url->request url #:default-scheme [default-scheme 'gopher])
(define url-components (regexp-match #px"^(\\w+://)?([a-zA-Z0-9\\-\\.]+)(:\\d+)?(/.*)?$" url))
(if url-components
(let ([protocol (string->protocol (second url-components) default-scheme)]
[host (third url-components)]
[port (fourth url-components)]
[path/selector (or (fifth url-components) "")])
(eprintf "url->request: ~a,~a,~a,~a~n" protocol host port path/selector)
(if (eq? protocol 'gemini)
(make-gemini-request protocol
host
port
path/selector)
(make-gopher-request protocol
host
port
path/selector)))
#f))
(define (request->url req)
(define (protocol->string p)
(cond
[(equal? p 'gopher) "gopher://"]
[(equal? p 'gemini) "gemini://"]
[(equal? p 'http) "http://"]
[else "gopher://"]))
(define (port-number->string port protocol)
(cond
[(equal? protocol 'gopher)
(if (= port 70)
""
(string-append ":" (number->string port)))]
[(equal? protocol 'gemini)
(if (= port 1965)
""
(string-append ":" (number->string port)))]
[(equal? protocol 'http)
(if (= port 80)
""
(string-append ":" (number->string port)))]))
(string-append (protocol->string (request-protocol req))
(request-host req)
(port-number->string (request-port req) (request-protocol req))
;; follow the convention of displaying the type in the URL. if selector is null add a '/' after the type
(if (request-type req)
(if (and (request-path/selector req) (not (equal? (request-path/selector req) "")))
(format "/~a" (request-type req))
(format "/~a/" (request-type req)))
"")
(request-path/selector req)))
;; there are two common ways to encode a URL into a gopher selector:
;; prefix with 'URL:' or use 'GET /' as the selector.
(define (gopher-url-request? req)
(define selector (request-path/selector req))
(or (string-prefix? selector "URL:")
(string-prefix? selector "GET /")))
(define (gopher-url-request->url req)
(define selector (request-path/selector req))
(cond
[(string-prefix? selector "URL:")
(string-trim selector "URL:" #:right? #f)]
[(string=? selector "GET /")
(string-append "http://" (request-host req) ":" (number->string (request-port req)))]
[else
selector]))
;; Helper functions
(define (string->protocol s [default 'gopher])
(cond
[(false? s) default]
[(equal? s "gopher://") 'gopher]
[(equal? s "gemini://") 'gemini]
[else 'unsupported]))
(define (default-port p)
(cond
[(equal? p 'gopher) 70]
[(equal? p 'gemini) 1965]
[(equal? p 'http) 80]
[else 70]))
(define (strip-type-from-path path protocol)
(if (and (equal? protocol 'gopher)
(> (string-length path) 2)
(and (equal? (string-ref path 0) #\/)
(equal? (string-ref path 2) #\/)))
(substring path 2)
path))
(define (get-type-from-path path protocol)
(if (and (equal? protocol 'gopher)
(> (string-length path) 2)
(and (equal? (string-ref path 0) #\/)
(equal? (string-ref path 2) #\/)))
(string-ref path 1)
#\1)) ; default to menu type
(define (make-gopher-request protocol host port path/selector)
(request protocol
host
(or (and (string? port) (string->number (substring port 1)))
(default-port protocol))
(strip-type-from-path path/selector protocol)
(get-type-from-path path/selector protocol)))
(define (make-gemini-request protocol host port path-plus-query)
;; prevent double slash at begining of path, can happen when url ending in slash is concatenated
;; with a path starting with a slash
(define sanitized-path
(if (string-prefix? path-plus-query "//")
(substring path-plus-query 1)
path-plus-query))
(request protocol
host
(or (and (string? port) (string->number (substring port 1)))
(default-port protocol))
(if (non-empty-string? sanitized-path) sanitized-path "/")
#f))