gohttp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +35 -0
- data/Rakefile +18 -0
- data/ext/gohttp/extconf.rb +18 -0
- data/ext/gohttp/gohttp.go +362 -0
- data/ext/gohttp/wrapper.go +105 -0
- data/gohttp.gemspec +29 -0
- data/lib/gohttp.rb +10 -0
- data/lib/gohttp/version.rb +3 -0
- data/test.rb +114 -0
- metadata +128 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6970bde6a9b5abb0c5dba6d1d24dd8d45e6d5f03
|
4
|
+
data.tar.gz: a49d93842ba8fbb32e5daf62c2cadfc406013d24
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 76290ca49818def17d3d107273b84811511d668539c3cecd01a79250d39ac50e52ad421ea6721177438c07936b7376024422950998e3cc45e44e6df22b181387
|
7
|
+
data.tar.gz: 37f5738e18ce5210bcca7afc3a13860138eb23021178cb5783537b2969d11bc53f07da103bc9710f73f6c4019510c8c5a3d679fa07a49409026f498334418828
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (C) 2015 NARUSE, Yui. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions
|
5
|
+
are met:
|
6
|
+
1. Redistributions of source code must retain the above copyright
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
10
|
+
documentation and/or other materials provided with the distribution.
|
11
|
+
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
13
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
14
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
15
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
16
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
17
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
18
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
19
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
20
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
21
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
22
|
+
SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Gohttp
|
2
|
+
|
3
|
+
A demo to implement a extension library with Go.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'gohttp'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install gohttp
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'gohttp'
|
25
|
+
r = Gohttp.get('https://example.com/index.html')
|
26
|
+
puts r.body.read
|
27
|
+
```
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it ( https://github.com/nurse/gohttp/fork )
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'rake/extensiontask'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
task :default => [:compile, :spec]
|
8
|
+
|
9
|
+
spec = eval File.read('gohttp.gemspec')
|
10
|
+
Rake::ExtensionTask.new('gohttp', spec) do |ext|
|
11
|
+
ext.ext_dir = 'ext/gohttp'
|
12
|
+
ext.lib_dir = File.join(*['lib', 'gohttp', ENV['FAT_DIR']].compact)
|
13
|
+
ext.source_pattern = "*.{c,cpp,go}"
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec::Core::RakeTask.new :spec do |spec|
|
17
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
find_executable('go')
|
3
|
+
$objs = []
|
4
|
+
def $objs.empty?; false ;end
|
5
|
+
create_makefile("gohttp/gohttp")
|
6
|
+
case `#{CONFIG['CC']} --version`
|
7
|
+
when /Free Software Foundation/
|
8
|
+
ldflags = '-Wl,--unresolved-symbols=ignore-all'
|
9
|
+
when /clang/
|
10
|
+
ldflags = '-undefined dynamic_lookup'
|
11
|
+
end
|
12
|
+
File.open('Makefile', 'a') do |f|
|
13
|
+
f.write <<eom.gsub(/^ {8}/, "\t")
|
14
|
+
$(DLLIB): Makefile $(srcdir)/gohttp.go $(srcdir)/wrapper.go
|
15
|
+
CGO_CFLAGS='$(INCFLAGS)' CGO_LDFLAGS='#{ldflags}' \
|
16
|
+
go build -p 4 -buildmode=c-shared -o $(DLLIB) $(srcdir)/gohttp.go $(srcdir)/wrapper.go
|
17
|
+
eom
|
18
|
+
end
|
@@ -0,0 +1,362 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
/*
|
4
|
+
#include <ruby/ruby.h>
|
5
|
+
|
6
|
+
VALUE NewGoStruct(VALUE klass, void *p);
|
7
|
+
void *GetGoStruct(VALUE obj);
|
8
|
+
|
9
|
+
VALUE gohttp_hello(VALUE);
|
10
|
+
VALUE gohttpGet(VALUE,VALUE);
|
11
|
+
VALUE gohttpHead(VALUE,VALUE);
|
12
|
+
int hash_of_ary_of_str2values_i(VALUE,VALUE,VALUE);
|
13
|
+
VALUE gohttpPostForm(VALUE,VALUE,VALUE);
|
14
|
+
VALUE gohttp_get_url(VALUE,VALUE);
|
15
|
+
VALUE gourlQueryEscape(VALUE,VALUE);
|
16
|
+
VALUE gourlQueryUnescape(VALUE,VALUE);
|
17
|
+
|
18
|
+
VALUE goio_to_s(VALUE);
|
19
|
+
VALUE goioRead(VALUE);
|
20
|
+
VALUE goioClose(VALUE);
|
21
|
+
|
22
|
+
VALUE reqMethod(VALUE);
|
23
|
+
VALUE reqURL(VALUE);
|
24
|
+
VALUE reqProto(VALUE);
|
25
|
+
VALUE reqHeader(VALUE);
|
26
|
+
VALUE reqBody(VALUE);
|
27
|
+
VALUE reqContentLength(VALUE);
|
28
|
+
VALUE reqTransferEncoding(VALUE);
|
29
|
+
VALUE reqHost(VALUE);
|
30
|
+
VALUE reqForm(VALUE);
|
31
|
+
VALUE reqForm(VALUE);
|
32
|
+
VALUE reqForm(VALUE);
|
33
|
+
VALUE reqForm(VALUE);
|
34
|
+
VALUE reqRemoteAddr(VALUE);
|
35
|
+
VALUE reqRequestURI(VALUE);
|
36
|
+
|
37
|
+
VALUE respContentLength(VALUE);
|
38
|
+
VALUE respStatus(VALUE);
|
39
|
+
VALUE respStatusCode(VALUE);
|
40
|
+
VALUE respProto(VALUE);
|
41
|
+
VALUE respTransferEncoding(VALUE);
|
42
|
+
VALUE respHeader(VALUE);
|
43
|
+
VALUE respBody(VALUE);
|
44
|
+
VALUE respRequest(VALUE);
|
45
|
+
*/
|
46
|
+
import "C"
|
47
|
+
|
48
|
+
import "fmt"
|
49
|
+
import "io"
|
50
|
+
import "io/ioutil"
|
51
|
+
import "net/http"
|
52
|
+
import "net/url"
|
53
|
+
import "reflect"
|
54
|
+
import "unsafe"
|
55
|
+
|
56
|
+
func main() {
|
57
|
+
}
|
58
|
+
|
59
|
+
var rb_cGoIO C.VALUE
|
60
|
+
var rb_cGohttp C.VALUE
|
61
|
+
var rb_cGourl C.VALUE
|
62
|
+
var rb_cRequest C.VALUE
|
63
|
+
var rb_cResponse C.VALUE
|
64
|
+
|
65
|
+
//export goobj_retain
|
66
|
+
func goobj_retain(obj unsafe.Pointer) {
|
67
|
+
objects[obj] = true
|
68
|
+
}
|
69
|
+
|
70
|
+
//export goobj_free
|
71
|
+
func goobj_free(obj unsafe.Pointer) {
|
72
|
+
delete(objects, obj)
|
73
|
+
}
|
74
|
+
|
75
|
+
func goioNew(klass C.VALUE, r interface{}) C.VALUE {
|
76
|
+
v := reflect.ValueOf(r)
|
77
|
+
return C.NewGoStruct(klass, unsafe.Pointer(&v))
|
78
|
+
}
|
79
|
+
|
80
|
+
//export goio_to_s
|
81
|
+
func goio_to_s(self C.VALUE) C.VALUE {
|
82
|
+
v := (*reflect.Value)(C.GetGoStruct(self))
|
83
|
+
switch v.Kind() {
|
84
|
+
case reflect.Struct:
|
85
|
+
return RbString(fmt.Sprintf("#<GoIO:%s>", v.Type().String()))
|
86
|
+
case reflect.Chan, reflect.Map, reflect.Ptr, reflect.UnsafePointer:
|
87
|
+
return RbString(fmt.Sprintf("#<GoIO:%s:0x%X>", v.Type().String(), v.Pointer()))
|
88
|
+
default:
|
89
|
+
return RbString(fmt.Sprintf("#<GoIO:%s>", v.Type().String()))
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
//export goioRead
|
94
|
+
func goioRead(self C.VALUE) C.VALUE {
|
95
|
+
v := (*reflect.Value)(C.GetGoStruct(self))
|
96
|
+
r := v.Interface().(io.Reader)
|
97
|
+
body, err := ioutil.ReadAll(r)
|
98
|
+
if err != nil {
|
99
|
+
rb_raise(C.rb_eArgError, "'%s'", err)
|
100
|
+
}
|
101
|
+
return RbBytes(body)
|
102
|
+
}
|
103
|
+
|
104
|
+
//export goioClose
|
105
|
+
func goioClose(self C.VALUE) C.VALUE {
|
106
|
+
v := (*reflect.Value)(C.GetGoStruct(self))
|
107
|
+
if c, ok := v.Interface().(io.Closer); ok {
|
108
|
+
c.Close()
|
109
|
+
return C.Qtrue
|
110
|
+
}
|
111
|
+
return C.Qfalse
|
112
|
+
}
|
113
|
+
|
114
|
+
func reqNew(klass C.VALUE, r *http.Request) C.VALUE {
|
115
|
+
return C.NewGoStruct(klass, unsafe.Pointer(r))
|
116
|
+
}
|
117
|
+
|
118
|
+
//export reqMethod
|
119
|
+
func reqMethod(self C.VALUE) C.VALUE {
|
120
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
121
|
+
return RbString(req.Method)
|
122
|
+
}
|
123
|
+
|
124
|
+
//export reqProto
|
125
|
+
func reqProto(self C.VALUE) C.VALUE {
|
126
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
127
|
+
return RbString(req.Proto)
|
128
|
+
}
|
129
|
+
|
130
|
+
//export reqHeader
|
131
|
+
func reqHeader(self C.VALUE) C.VALUE {
|
132
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
133
|
+
h := C.rb_hash_new()
|
134
|
+
for key, value := range req.Header {
|
135
|
+
C.rb_hash_aset(h, RbString(key), StrSlice2RbArray(value))
|
136
|
+
}
|
137
|
+
return h
|
138
|
+
}
|
139
|
+
|
140
|
+
//export reqBody
|
141
|
+
func reqBody(self C.VALUE) C.VALUE {
|
142
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
143
|
+
if req.Body == nil {
|
144
|
+
return C.Qnil
|
145
|
+
}
|
146
|
+
return goioNew(rb_cGoIO, req.Body)
|
147
|
+
}
|
148
|
+
|
149
|
+
//export reqContentLength
|
150
|
+
func reqContentLength(self C.VALUE) C.VALUE {
|
151
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
152
|
+
return INT64toNUM(req.ContentLength)
|
153
|
+
}
|
154
|
+
|
155
|
+
//export reqTransferEncoding
|
156
|
+
func reqTransferEncoding(self C.VALUE) C.VALUE {
|
157
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
158
|
+
return StrSlice2RbArray(req.TransferEncoding)
|
159
|
+
}
|
160
|
+
|
161
|
+
//export reqHost
|
162
|
+
func reqHost(self C.VALUE) C.VALUE {
|
163
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
164
|
+
return RbString(req.Host)
|
165
|
+
}
|
166
|
+
|
167
|
+
//export reqRemoteAddr
|
168
|
+
func reqRemoteAddr(self C.VALUE) C.VALUE {
|
169
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
170
|
+
return RbString(req.RemoteAddr)
|
171
|
+
}
|
172
|
+
|
173
|
+
//export reqRequestURI
|
174
|
+
func reqRequestURI(self C.VALUE) C.VALUE {
|
175
|
+
req := (*http.Request)(C.GetGoStruct(self))
|
176
|
+
return RbString(req.RequestURI)
|
177
|
+
}
|
178
|
+
|
179
|
+
func respNew(klass C.VALUE, r *http.Response) C.VALUE {
|
180
|
+
return C.NewGoStruct(klass, unsafe.Pointer(r))
|
181
|
+
}
|
182
|
+
|
183
|
+
//export respContentLength
|
184
|
+
func respContentLength(self C.VALUE) C.VALUE {
|
185
|
+
resp := (*http.Response)(C.GetGoStruct(self))
|
186
|
+
return INT64toNUM(resp.ContentLength)
|
187
|
+
}
|
188
|
+
|
189
|
+
//export respHeader
|
190
|
+
func respHeader(self C.VALUE) C.VALUE {
|
191
|
+
resp := (*http.Response)(C.GetGoStruct(self))
|
192
|
+
h := C.rb_hash_new()
|
193
|
+
for key, value := range resp.Header {
|
194
|
+
C.rb_hash_aset(h, RbString(key), StrSlice2RbArray(value))
|
195
|
+
}
|
196
|
+
return h
|
197
|
+
}
|
198
|
+
|
199
|
+
//export respStatus
|
200
|
+
func respStatus(self C.VALUE) C.VALUE {
|
201
|
+
resp := (*http.Response)(C.GetGoStruct(self))
|
202
|
+
return RbString(resp.Status)
|
203
|
+
}
|
204
|
+
|
205
|
+
//export respStatusCode
|
206
|
+
func respStatusCode(self C.VALUE) C.VALUE {
|
207
|
+
resp := (*http.Response)(C.GetGoStruct(self))
|
208
|
+
return INT2NUM(resp.StatusCode)
|
209
|
+
}
|
210
|
+
|
211
|
+
//export respProto
|
212
|
+
func respProto(self C.VALUE) C.VALUE {
|
213
|
+
resp := (*http.Response)(C.GetGoStruct(self))
|
214
|
+
return RbString(resp.Proto)
|
215
|
+
}
|
216
|
+
|
217
|
+
//export respTransferEncoding
|
218
|
+
func respTransferEncoding(self C.VALUE) C.VALUE {
|
219
|
+
resp := (*http.Response)(C.GetGoStruct(self))
|
220
|
+
return StrSlice2RbArray(resp.TransferEncoding)
|
221
|
+
}
|
222
|
+
|
223
|
+
//export respBody
|
224
|
+
func respBody(self C.VALUE) C.VALUE {
|
225
|
+
resp := (*http.Response)(C.GetGoStruct(self))
|
226
|
+
if resp.Body == nil {
|
227
|
+
return C.Qnil
|
228
|
+
}
|
229
|
+
return goioNew(rb_cGoIO, resp.Body)
|
230
|
+
}
|
231
|
+
|
232
|
+
//export respRequest
|
233
|
+
func respRequest(self C.VALUE) C.VALUE {
|
234
|
+
resp := (*http.Response)(C.GetGoStruct(self))
|
235
|
+
return reqNew(rb_cRequest, resp.Request)
|
236
|
+
}
|
237
|
+
|
238
|
+
//export gohttp_hello
|
239
|
+
func gohttp_hello(dummy C.VALUE) C.VALUE {
|
240
|
+
fmt.Printf("hello, world\n")
|
241
|
+
return C.Qnil
|
242
|
+
}
|
243
|
+
|
244
|
+
//export gohttpGet
|
245
|
+
func gohttpGet(dummy C.VALUE, urlstr C.VALUE) C.VALUE {
|
246
|
+
str := RbGoString(urlstr)
|
247
|
+
resp, err := http.Get(str)
|
248
|
+
if err != nil {
|
249
|
+
rb_raise(C.rb_eArgError, "'%s'", err)
|
250
|
+
}
|
251
|
+
return respNew(rb_cResponse, resp)
|
252
|
+
}
|
253
|
+
|
254
|
+
//export gohttpHead
|
255
|
+
func gohttpHead(dummy C.VALUE, urlstr C.VALUE) C.VALUE {
|
256
|
+
str := RbGoString(urlstr)
|
257
|
+
resp, err := http.Head(str)
|
258
|
+
if err != nil {
|
259
|
+
rb_raise(C.rb_eArgError, "'%s'", err)
|
260
|
+
}
|
261
|
+
return respNew(rb_cResponse, resp)
|
262
|
+
}
|
263
|
+
|
264
|
+
//export hash_of_ary_of_str2values_i
|
265
|
+
func hash_of_ary_of_str2values_i(key C.VALUE, ary C.VALUE, arg C.VALUE) C.int {
|
266
|
+
values := (*url.Values)(unsafe.Pointer(uintptr(arg)))
|
267
|
+
values.Add(RbGoString(key), RbGoString(ary))
|
268
|
+
return C.ST_CONTINUE
|
269
|
+
}
|
270
|
+
|
271
|
+
//export gohttpPostForm
|
272
|
+
func gohttpPostForm(dummy C.VALUE, urlstr C.VALUE, data C.VALUE) C.VALUE {
|
273
|
+
str := RbGoString(urlstr)
|
274
|
+
val := url.Values{}
|
275
|
+
C.rb_hash_foreach(data, (*[0]byte)(C.hash_of_ary_of_str2values_i), C.VALUE(uintptr(unsafe.Pointer(&val))))
|
276
|
+
resp, err := http.PostForm(str, val)
|
277
|
+
if err != nil {
|
278
|
+
rb_raise(C.rb_eArgError, "'%s'", err)
|
279
|
+
}
|
280
|
+
return respNew(rb_cResponse, resp)
|
281
|
+
}
|
282
|
+
|
283
|
+
//export gohttp_get_url
|
284
|
+
func gohttp_get_url(dummy C.VALUE, urlstr C.VALUE) C.VALUE {
|
285
|
+
u, err := url.Parse(RbGoString(urlstr))
|
286
|
+
if err != nil {
|
287
|
+
return C.Qnil
|
288
|
+
}
|
289
|
+
return RbString(u.String())
|
290
|
+
}
|
291
|
+
|
292
|
+
//export gourlQueryEscape
|
293
|
+
func gourlQueryEscape(dummy C.VALUE, s C.VALUE) C.VALUE {
|
294
|
+
return RbString(url.QueryEscape(RbGoString(s)))
|
295
|
+
}
|
296
|
+
|
297
|
+
//export gourlQueryUnescape
|
298
|
+
func gourlQueryUnescape(dummy C.VALUE, s C.VALUE) C.VALUE {
|
299
|
+
src := RbGoString(s)
|
300
|
+
str, err := url.QueryUnescape(src)
|
301
|
+
if err != nil {
|
302
|
+
rb_raise(C.rb_eArgError, "'%s' is not valid pct-encoded", src)
|
303
|
+
}
|
304
|
+
return RbString(str)
|
305
|
+
}
|
306
|
+
|
307
|
+
//export Init_gohttp
|
308
|
+
func Init_gohttp() {
|
309
|
+
sNew := "new"
|
310
|
+
str_new := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&sNew)))[0]))
|
311
|
+
|
312
|
+
rb_cGoIO = rb_define_class("GoIO", C.rb_cIO)
|
313
|
+
C.rb_undef_alloc_func(rb_cGoIO)
|
314
|
+
C.rb_undef_method(C.rb_class_of(rb_cGoIO), str_new)
|
315
|
+
rb_define_method(rb_cGoIO, "to_s", C.goio_to_s, 0)
|
316
|
+
rb_define_method(rb_cGoIO, "inspect", C.goio_to_s, 0)
|
317
|
+
rb_define_method(rb_cGoIO, "read", C.goioRead, 0)
|
318
|
+
rb_define_method(rb_cGoIO, "close", C.goioClose, 0)
|
319
|
+
|
320
|
+
rb_cRequest = rb_define_class("Request", C.rb_cObject)
|
321
|
+
C.rb_undef_alloc_func(rb_cRequest)
|
322
|
+
C.rb_undef_method(C.rb_class_of(rb_cRequest), str_new)
|
323
|
+
rb_define_method(rb_cRequest, "method", C.reqMethod, 0)
|
324
|
+
//rb_define_method(rb_cRequest, "url", C.reqURL, 0)
|
325
|
+
rb_define_method(rb_cRequest, "proto", C.reqProto, 0)
|
326
|
+
rb_define_method(rb_cRequest, "header", C.reqHeader, 0)
|
327
|
+
rb_define_method(rb_cRequest, "body", C.reqBody, 0)
|
328
|
+
rb_define_method(rb_cRequest, "content_length", C.reqContentLength, 0)
|
329
|
+
rb_define_method(rb_cRequest, "transfer_encoding", C.reqTransferEncoding, 0)
|
330
|
+
rb_define_method(rb_cRequest, "host", C.reqHost, 0)
|
331
|
+
//rb_define_method(rb_cRequest, "form", C.reqForm, 0)
|
332
|
+
//rb_define_method(rb_cRequest, "post_form", C.reqForm, 0)
|
333
|
+
//rb_define_method(rb_cRequest, "multipart_form", C.reqForm, 0)
|
334
|
+
//rb_define_method(rb_cRequest, "trailer", C.reqForm, 0)
|
335
|
+
rb_define_method(rb_cRequest, "remote_addr", C.reqRemoteAddr, 0)
|
336
|
+
rb_define_method(rb_cRequest, "request_uri", C.reqRequestURI, 0)
|
337
|
+
|
338
|
+
rb_cResponse = rb_define_class("Response", C.rb_cObject)
|
339
|
+
C.rb_undef_alloc_func(rb_cResponse)
|
340
|
+
C.rb_undef_method(C.rb_class_of(rb_cResponse), str_new)
|
341
|
+
rb_define_method(rb_cResponse, "size", C.respContentLength, 0)
|
342
|
+
rb_define_method(rb_cResponse, "status", C.respStatus, 0)
|
343
|
+
rb_define_method(rb_cResponse, "status_code", C.respStatusCode, 0)
|
344
|
+
rb_define_method(rb_cResponse, "proto", C.respProto, 0)
|
345
|
+
rb_define_method(rb_cResponse, "transfer_encoding", C.respTransferEncoding, 0)
|
346
|
+
rb_define_method(rb_cResponse, "header", C.respHeader, 0)
|
347
|
+
rb_define_method(rb_cResponse, "body", C.respBody, 0)
|
348
|
+
rb_define_method(rb_cResponse, "request", C.respRequest, 0)
|
349
|
+
|
350
|
+
rb_cGohttp = rb_define_class("Gohttp", C.rb_cObject)
|
351
|
+
rb_define_singleton_method(rb_cGohttp, "hello", C.gohttp_hello, 0)
|
352
|
+
rb_define_singleton_method(rb_cGohttp, "get", C.gohttpGet, 1)
|
353
|
+
rb_define_singleton_method(rb_cGohttp, "head", C.gohttpHead, 1)
|
354
|
+
//rb_define_singleton_method(rb_cGohttp, "post", C.gohttpPost, 1)
|
355
|
+
rb_define_singleton_method(rb_cGohttp, "post_form", C.gohttpPostForm, 2)
|
356
|
+
//rb_define_method(rb_cGohttp, "initialize", C.gohttp_initialize, 1)
|
357
|
+
rb_define_method(rb_cGohttp, "get_url", C.gohttp_get_url, 1)
|
358
|
+
|
359
|
+
rb_cGourl = rb_define_class("Gourl", C.rb_cObject)
|
360
|
+
rb_define_singleton_method(rb_cGourl, "query_escape", C.gourlQueryEscape, 1)
|
361
|
+
rb_define_singleton_method(rb_cGourl, "query_unescape", C.gourlQueryUnescape, 1)
|
362
|
+
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
/*
|
4
|
+
#include <ruby/ruby.h>
|
5
|
+
|
6
|
+
const char *
|
7
|
+
rstring_ptr(VALUE str) {
|
8
|
+
return RSTRING_PTR(str);
|
9
|
+
}
|
10
|
+
int
|
11
|
+
rstring_len(VALUE str) {
|
12
|
+
return RSTRING_LENINT(str);
|
13
|
+
}
|
14
|
+
void
|
15
|
+
rb_raise2(VALUE exc, const char *str) {
|
16
|
+
rb_raise(exc, "%s", str);
|
17
|
+
}
|
18
|
+
|
19
|
+
void goobj_retain(void *);
|
20
|
+
void goobj_free(void *);
|
21
|
+
|
22
|
+
static const rb_data_type_t go_type = {
|
23
|
+
"GoStruct",
|
24
|
+
{NULL, goobj_free, NULL},
|
25
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
|
26
|
+
};
|
27
|
+
|
28
|
+
VALUE
|
29
|
+
NewGoStruct(VALUE klass, void *p)
|
30
|
+
{
|
31
|
+
goobj_retain(p);
|
32
|
+
return TypedData_Wrap_Struct((klass), &go_type, p);
|
33
|
+
}
|
34
|
+
|
35
|
+
void *
|
36
|
+
GetGoStruct(VALUE obj)
|
37
|
+
{
|
38
|
+
void *val;
|
39
|
+
return TypedData_Get_Struct((obj), void *, &go_type, (val));
|
40
|
+
}
|
41
|
+
*/
|
42
|
+
import "C"
|
43
|
+
import "unsafe"
|
44
|
+
import "fmt"
|
45
|
+
|
46
|
+
var objects = make(map[interface{}]bool)
|
47
|
+
|
48
|
+
func rb_define_method(klass C.VALUE, name string, fun unsafe.Pointer, args int) {
|
49
|
+
cname := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&name)))[0]))
|
50
|
+
C.rb_define_method(klass, cname, (*[0]byte)(fun), C.int(args))
|
51
|
+
}
|
52
|
+
|
53
|
+
func rb_define_singleton_method(klass C.VALUE, name string, fun unsafe.Pointer, args int) {
|
54
|
+
cname := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&name)))[0]))
|
55
|
+
C.rb_define_singleton_method(klass, cname, (*[0]byte)(fun), C.int(args))
|
56
|
+
}
|
57
|
+
|
58
|
+
func RbGoString(str C.VALUE) string {
|
59
|
+
C.rb_string_value(&str)
|
60
|
+
return C.GoStringN(C.rstring_ptr(str), C.rstring_len(str))
|
61
|
+
}
|
62
|
+
|
63
|
+
func RbBytes(bytes []byte) C.VALUE {
|
64
|
+
if len(bytes) == 0 {
|
65
|
+
return C.rb_str_new(nil, C.long(0))
|
66
|
+
}
|
67
|
+
cstr := (*C.char)(unsafe.Pointer(&bytes[0]))
|
68
|
+
return C.rb_str_new(cstr, C.long(len(bytes)))
|
69
|
+
}
|
70
|
+
|
71
|
+
func RbString(str string) C.VALUE {
|
72
|
+
if len(str) == 0 {
|
73
|
+
return C.rb_utf8_str_new(nil, C.long(0))
|
74
|
+
}
|
75
|
+
cstr := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&str)))[0]))
|
76
|
+
return C.rb_utf8_str_new(cstr, C.long(len(str)))
|
77
|
+
}
|
78
|
+
|
79
|
+
func rb_define_class(name string, parent C.VALUE) C.VALUE {
|
80
|
+
cname := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&name)))[0]))
|
81
|
+
v := C.rb_define_class(cname, parent)
|
82
|
+
return v
|
83
|
+
}
|
84
|
+
|
85
|
+
func rb_raise(exc C.VALUE, format string, a ...interface{}) {
|
86
|
+
str := fmt.Sprintf(format, a...)
|
87
|
+
cstr := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&str)))[0]))
|
88
|
+
C.rb_raise2(exc, cstr)
|
89
|
+
}
|
90
|
+
|
91
|
+
func INT2NUM(n int) C.VALUE {
|
92
|
+
return C.rb_int2inum(C.long(n))
|
93
|
+
}
|
94
|
+
|
95
|
+
func INT64toNUM(n int64) C.VALUE {
|
96
|
+
return C.rb_ll2inum(C.longlong(n))
|
97
|
+
}
|
98
|
+
|
99
|
+
func StrSlice2RbArray(slice []string) C.VALUE {
|
100
|
+
ary := C.rb_ary_new_capa(C.long(len(slice)))
|
101
|
+
for _, val := range slice {
|
102
|
+
C.rb_ary_push(ary, RbString(val))
|
103
|
+
}
|
104
|
+
return ary
|
105
|
+
}
|
data/gohttp.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gohttp/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gohttp"
|
8
|
+
spec.version = Strptime::VERSION
|
9
|
+
spec.authors = ["NARUSE, Yui"]
|
10
|
+
spec.email = ["naruse@airemix.jp"]
|
11
|
+
|
12
|
+
spec.summary = %q{an http library with go.}
|
13
|
+
spec.description = %q{an http library with go.}
|
14
|
+
spec.homepage = "https://github.com/nurse/gohttp"
|
15
|
+
spec.license = "BSD-2-Clause"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
spec.extensions = ["ext/gohttp/extconf.rb"]
|
22
|
+
spec.required_ruby_version = '~> 2.0'
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rake-compiler"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency 'yard'
|
29
|
+
end
|
data/lib/gohttp.rb
ADDED
data/test.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'gohttp'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
class TestGohttp < Minitest::Test
|
7
|
+
def test_hello
|
8
|
+
assert_output("hello, world\n") do
|
9
|
+
Gohttp.hello
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_hello
|
14
|
+
o = Object.new
|
15
|
+
def o.to_str; "https://例え.テスト/ファイル.html"; end
|
16
|
+
g = Gohttp.new
|
17
|
+
assert_equal "https://%E4%BE%8B%E3%81%88.%E3%83%86%E3%82%B9%E3%83%88/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.html", g.get_url(o)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_get
|
21
|
+
r = Gohttp.get('https://example.com/index.html')
|
22
|
+
assert_kind_of Response, r
|
23
|
+
assert_equal '200 OK', r.status
|
24
|
+
assert_equal 200, r.status_code
|
25
|
+
assert_equal 'HTTP/1.1', r.proto
|
26
|
+
assert_equal 1270, r.size
|
27
|
+
assert_equal [], r.transfer_encoding
|
28
|
+
hdr = r.header
|
29
|
+
assert_kind_of Hash, hdr
|
30
|
+
assert_equal %w[max-age=604800], hdr["Cache-Control"]
|
31
|
+
assert_equal %w[text/html], hdr["Content-Type"]
|
32
|
+
b = r.body
|
33
|
+
assert_match /\A#<GoIO:\*http.bodyEOFSignal:0x\h+>/, b.to_s
|
34
|
+
assert_match /Example Domain/, b.read
|
35
|
+
assert_equal true, b.close
|
36
|
+
req = r.request
|
37
|
+
assert_equal 'GET', req.method
|
38
|
+
assert_equal 'HTTP/1.1', req.proto
|
39
|
+
assert_equal Hash[], req.header
|
40
|
+
assert_nil req.body
|
41
|
+
assert_equal 0, req.content_length
|
42
|
+
assert_equal [], req.transfer_encoding
|
43
|
+
assert_equal 'example.com', req.host
|
44
|
+
assert_equal '', req.remote_addr
|
45
|
+
assert_equal '', req.request_uri
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_head
|
49
|
+
r = Gohttp.head('https://example.com/index.html')
|
50
|
+
assert_kind_of Response, r
|
51
|
+
assert_equal '200 OK', r.status
|
52
|
+
assert_equal 200, r.status_code
|
53
|
+
assert_equal 'HTTP/1.1', r.proto
|
54
|
+
assert_equal 1270, r.size
|
55
|
+
assert_equal [], r.transfer_encoding
|
56
|
+
hdr = r.header
|
57
|
+
assert_kind_of Hash, hdr
|
58
|
+
assert_equal %w[max-age=604800], hdr["Cache-Control"]
|
59
|
+
assert_equal %w[text/html], hdr["Content-Type"]
|
60
|
+
b = r.body
|
61
|
+
assert_match /\A#<GoIO:\*http.bodyEOFSignal>/, b.to_s
|
62
|
+
assert_match '', b.read
|
63
|
+
assert_equal true, b.close
|
64
|
+
req = r.request
|
65
|
+
assert_equal 'HEAD', req.method
|
66
|
+
assert_equal 'HTTP/1.1', req.proto
|
67
|
+
assert_equal Hash[], req.header
|
68
|
+
assert_nil req.body
|
69
|
+
assert_equal 0, req.content_length
|
70
|
+
assert_equal [], req.transfer_encoding
|
71
|
+
assert_equal 'example.com', req.host
|
72
|
+
assert_equal '', req.remote_addr
|
73
|
+
assert_equal '', req.request_uri
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_head
|
77
|
+
r = Gohttp.post_form('http://nalsh.jp/env.cgi', {'foo' => 'bar'})
|
78
|
+
assert_kind_of Response, r
|
79
|
+
assert_equal '200 OK', r.status
|
80
|
+
assert_equal 200, r.status_code
|
81
|
+
assert_equal 'HTTP/1.1', r.proto
|
82
|
+
assert_equal -1, r.size
|
83
|
+
assert_equal %w[chunked], r.transfer_encoding
|
84
|
+
hdr = r.header
|
85
|
+
assert_kind_of Hash, hdr
|
86
|
+
assert_equal nil, hdr["Cache-Control"]
|
87
|
+
assert_equal %w[text/html], hdr["Content-Type"]
|
88
|
+
b = r.body
|
89
|
+
assert_match /\A#<GoIO:\*http.bodyEOFSignal:0x\h+>/, b.to_s
|
90
|
+
assert_match '', b.read
|
91
|
+
assert_equal true, b.close
|
92
|
+
req = r.request
|
93
|
+
assert_equal 'POST', req.method
|
94
|
+
assert_equal 'HTTP/1.1', req.proto
|
95
|
+
assert_equal Hash["Content-Type"=>["application/x-www-form-urlencoded"]], req.header
|
96
|
+
assert_match /\A#<GoIO:ioutil.nopCloser>\z/, req.body.to_s
|
97
|
+
assert_equal 7, req.content_length
|
98
|
+
assert_equal [], req.transfer_encoding
|
99
|
+
assert_equal 'nalsh.jp', req.host
|
100
|
+
assert_equal '', req.remote_addr
|
101
|
+
assert_equal '', req.request_uri
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class TestGourl < Minitest::Test
|
106
|
+
def test_escape
|
107
|
+
assert_equal '%E3%81%82+%2B', Gourl.query_escape('あ +')
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_escape
|
111
|
+
assert_equal 'あ ', Gourl.query_unescape('%E3%81%82%20+')
|
112
|
+
assert_raises(ArgumentError){ Gourl.query_unescape('%%81%82%20+') }
|
113
|
+
end
|
114
|
+
end
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gohttp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- NARUSE, Yui
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-11-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake-compiler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: an http library with go.
|
84
|
+
email:
|
85
|
+
- naruse@airemix.jp
|
86
|
+
executables: []
|
87
|
+
extensions:
|
88
|
+
- ext/gohttp/extconf.rb
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- ext/gohttp/extconf.rb
|
97
|
+
- ext/gohttp/gohttp.go
|
98
|
+
- ext/gohttp/wrapper.go
|
99
|
+
- gohttp.gemspec
|
100
|
+
- lib/gohttp.rb
|
101
|
+
- lib/gohttp/version.rb
|
102
|
+
- test.rb
|
103
|
+
homepage: https://github.com/nurse/gohttp
|
104
|
+
licenses:
|
105
|
+
- BSD-2-Clause
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '2.0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.4.5
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: an http library with go.
|
127
|
+
test_files: []
|
128
|
+
has_rdoc:
|