diff options
Diffstat (limited to 'libgemini.go')
-rw-r--r-- | libgemini.go | 153 |
1 files changed, 0 insertions, 153 deletions
diff --git a/libgemini.go b/libgemini.go deleted file mode 100644 index 94744ba..0000000 --- a/libgemini.go +++ /dev/null | |||
@@ -1,153 +0,0 @@ | |||
1 | package gopherproxy | ||
2 | |||
3 | import ( | ||
4 | "bufio" | ||
5 | "crypto/tls" | ||
6 | "errors" | ||
7 | "io" | ||
8 | "mime" | ||
9 | "net/url" | ||
10 | "regexp" | ||
11 | "strconv" | ||
12 | "strings" | ||
13 | ) | ||
14 | |||
15 | const ( | ||
16 | CRLF = "\r\n" | ||
17 | ) | ||
18 | |||
19 | const ( | ||
20 | STATUS_INPUT = 10 | ||
21 | STATUS_SUCCESS = 20 | ||
22 | STATUS_SUCCESS_CERT = 21 | ||
23 | STATUS_REDIRECT_TEMP = 30 | ||
24 | STATUS_REDIRECT_PERM = 31 | ||
25 | STATUS_TEMP_FAILURE = 40 | ||
26 | STATUS_SERVER_UNAVAILABLE = 41 | ||
27 | STATUS_CGI_ERROR = 42 | ||
28 | STATUS_PROXY_ERROR = 43 | ||
29 | STATUS_SLOW_DOWN = 44 | ||
30 | STATUS_PERM_FAILURE = 50 | ||
31 | STATUS_NOT_FOUND = 51 | ||
32 | STATUS_GONE = 52 | ||
33 | STATUS_PROXY_REFUSED = 53 | ||
34 | STATUS_BAD_REQUEST = 59 | ||
35 | STATUS_CLIENT_CERT_EXPIRED = 60 | ||
36 | STATUS_TRANSIENT_CERT_REQUEST = 61 | ||
37 | STATUS_AUTH_CERT_REQUIRED = 62 | ||
38 | STATUS_CERT_REJECTED = 63 | ||
39 | STATUS_FUTURE_CERT_REJECTED = 64 | ||
40 | STATUS_EXPIRED_CERT_REJECTED = 65 | ||
41 | ) | ||
42 | |||
43 | const ( | ||
44 | MIME_GEMINI = "text/gemini" | ||
45 | DEFAULT_MIME = MIME_GEMINI | ||
46 | DEFAULT_CHARSET = "utf-8" | ||
47 | ) | ||
48 | |||
49 | var ( | ||
50 | HeaderPattern = regexp.MustCompile("^(\\d\\d)[ \\t]+(.*)$") | ||
51 | GeminiLinkPattern = regexp.MustCompile("^=>[ \\t]*([^ \\t]+)(?:[ \\t]+(.*))?$") | ||
52 | ) | ||
53 | |||
54 | type GeminiHeader struct { | ||
55 | Status int | ||
56 | Meta string | ||
57 | } | ||
58 | |||
59 | type GeminiResponse struct { | ||
60 | Header *GeminiHeader | ||
61 | Body io.Reader | ||
62 | } | ||
63 | |||
64 | func GeminiGet(uri string) (*GeminiResponse, error) { | ||
65 | u, err := url.Parse(uri) | ||
66 | if err != nil { | ||
67 | return nil, err | ||
68 | } | ||
69 | |||
70 | if u.Scheme != "gemini" { | ||
71 | return nil, errors.New("invalid scheme for uri") | ||
72 | } | ||
73 | |||
74 | var ( | ||
75 | host string | ||
76 | port int | ||
77 | ) | ||
78 | |||
79 | hostport := strings.Split(u.Host, ":") | ||
80 | if len(hostport) == 2 { | ||
81 | host = hostport[0] | ||
82 | n, err := strconv.ParseInt(hostport[1], 10, 32) | ||
83 | if err != nil { | ||
84 | return nil, err | ||
85 | } | ||
86 | port = int(n) | ||
87 | } else { | ||
88 | host, port = hostport[0], 1965 | ||
89 | } | ||
90 | |||
91 | conn, err := tls.Dial("tcp", host+":"+strconv.Itoa(port), &tls.Config{ | ||
92 | MinVersion: tls.VersionTLS12, | ||
93 | InsecureSkipVerify: true, | ||
94 | }) | ||
95 | if err != nil { | ||
96 | return nil, err | ||
97 | } | ||
98 | |||
99 | _, err = conn.Write([]byte(u.String() + CRLF)) | ||
100 | if err != nil { | ||
101 | conn.Close() | ||
102 | return nil, err | ||
103 | } | ||
104 | |||
105 | reader := bufio.NewReader(conn) | ||
106 | |||
107 | line, _, err := reader.ReadLine() | ||
108 | if err != nil { | ||
109 | conn.Close() | ||
110 | return nil, err | ||
111 | } | ||
112 | |||
113 | header, err := ParseGeminiHeader(string(line)) | ||
114 | if err != nil { | ||
115 | conn.Close() | ||
116 | return nil, err | ||
117 | } | ||
118 | |||
119 | return &GeminiResponse{ | ||
120 | Header: header, | ||
121 | Body: reader, | ||
122 | }, nil | ||
123 | } | ||
124 | |||
125 | func ParseGeminiHeader(line string) (header *GeminiHeader, err error) { | ||
126 | matches := HeaderPattern.FindStringSubmatch(line) | ||
127 | |||
128 | status, err := strconv.Atoi(matches[1]) | ||
129 | if err != nil { | ||
130 | return nil, err | ||
131 | } | ||
132 | |||
133 | meta := matches[2] | ||
134 | |||
135 | if int(status/10) == 2 { | ||
136 | mediaType, params, err := mime.ParseMediaType(meta) | ||
137 | |||
138 | if err != nil { | ||
139 | meta = DEFAULT_MIME + ";charset=" + DEFAULT_CHARSET | ||
140 | } else if strings.HasPrefix(mediaType, "text/") { | ||
141 | if _, ok := params["charset"]; !ok { | ||
142 | meta += ";charset=" + DEFAULT_CHARSET | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | |||
147 | header = &GeminiHeader{ | ||
148 | Status: status, | ||
149 | Meta: meta, | ||
150 | } | ||
151 | |||
152 | return | ||
153 | } | ||