Skip to content
This repository was archived by the owner on Jul 12, 2025. It is now read-only.

Commit 557bbca

Browse files
authored
Merge pull request #866 from aisk/http-methods
Add missing delete / options method to http module
2 parents 1dd1905 + 0f50e29 commit 557bbca

File tree

2 files changed

+81
-47
lines changed

2 files changed

+81
-47
lines changed

vm/http.go

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ var builtinHTTPClassMethods = []*BuiltinMethodObject{
3838
}
3939

4040
uri, err := url.Parse(arg0.value)
41+
if err != nil {
42+
return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
43+
}
4144

4245
if len(args) > 1 {
4346
var arr []string
@@ -119,50 +122,19 @@ var builtinHTTPClassMethods = []*BuiltinMethodObject{
119122
// Sends a HEAD request to the target with type header and body. Returns the HTTP headers as a map[string]string. Will error on non-200 responses, for more control over http requests look at the `start` method.
120123
Name: "head",
121124
Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
122-
if len(args) < 1 {
123-
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentMore, 1, len(args))
124-
}
125-
126-
arg0, ok := args[0].(*StringObject)
127-
if !ok {
128-
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 0, "String", args[0].Class().Name)
129-
}
130-
131-
uri, err := url.Parse(arg0.value)
132-
if err != nil {
133-
return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
134-
}
135-
136-
if len(args) > 1 {
137-
var arr []string
138-
139-
for i, v := range args[1:] {
140-
argn, ok := v.(*StringObject)
141-
if !ok {
142-
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, invalidSplatArgument, v.Class().Name, i)
143-
}
144-
arr = append(arr, argn.value)
145-
}
146-
147-
uri.Path = path.Join(arr...)
148-
}
149-
150-
resp, err := http.Head(uri.String())
151-
if err != nil {
152-
return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
153-
}
154-
if resp.StatusCode != http.StatusOK {
155-
return t.vm.InitErrorObject(errors.HTTPError, sourceLine, non200Response, resp.Status, resp.StatusCode)
156-
}
157-
158-
ret := t.vm.InitHashObject(map[string]Object{})
159-
160-
for k, v := range resp.Header {
161-
ret.Pairs[k] = t.vm.InitStringObject(strings.Join(v, " "))
162-
}
163-
164-
return ret
165-
125+
return httpMethodWithoutBody("HEAD", receiver, sourceLine, t, args, blockFrame)
126+
},
127+
}, {
128+
// Sends a DELETE request to the target with type header and body. Returns the HTTP headers as a map[string]string. Will error on non-200 responses, for more control over http requests look at the `start` method.
129+
Name: "delete",
130+
Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
131+
return httpMethodWithoutBody("DELETE", receiver, sourceLine, t, args, blockFrame)
132+
},
133+
}, {
134+
// Sends a OPTIONS request to the target with type header and body. Returns the HTTP headers as a map[string]string. Will error on non-200 responses, for more control over http requests look at the `start` method.
135+
Name: "options",
136+
Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
137+
return httpMethodWithoutBody("OPTIONS", receiver, sourceLine, t, args, blockFrame)
166138
},
167139
}, {
168140
// Starts an HTTP client. This method requires a block which takes a Net::HTTP::Client object. The return value of this method is the last evaluated value of the provided block.
@@ -187,6 +159,55 @@ var builtinHTTPClassMethods = []*BuiltinMethodObject{
187159
}
188160

189161
// Internal functions ===================================================
162+
func httpMethodWithoutBody(method string, receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
163+
if len(args) < 1 {
164+
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentMore, 1, len(args))
165+
}
166+
167+
arg0, ok := args[0].(*StringObject)
168+
if !ok {
169+
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 0, "String", args[0].Class().Name)
170+
}
171+
172+
uri, err := url.Parse(arg0.value)
173+
if err != nil {
174+
return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
175+
}
176+
177+
if len(args) > 1 {
178+
var arr []string
179+
180+
for i, v := range args[1:] {
181+
argn, ok := v.(*StringObject)
182+
if !ok {
183+
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, invalidSplatArgument, v.Class().Name, i)
184+
}
185+
arr = append(arr, argn.value)
186+
}
187+
188+
uri.Path = path.Join(arr...)
189+
}
190+
191+
req, err := http.NewRequest(method, uri.String(), nil)
192+
if err != nil {
193+
return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
194+
}
195+
resp, err := http.DefaultClient.Do(req)
196+
if err != nil {
197+
return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
198+
}
199+
if resp.StatusCode != http.StatusOK {
200+
return t.vm.InitErrorObject(errors.HTTPError, sourceLine, non200Response, resp.Status, resp.StatusCode)
201+
}
202+
203+
ret := t.vm.InitHashObject(map[string]Object{})
204+
205+
for k, v := range resp.Header {
206+
ret.Pairs[k] = t.vm.InitStringObject(strings.Join(v, " "))
207+
}
208+
209+
return ret
210+
}
190211

191212
// Functions for initialization -----------------------------------------
192213

vm/http_test.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,20 @@ func TestHTTPRequest(t *testing.T) {
3636
require "net/http"
3737
3838
res = Net::HTTP.head("http://127.0.0.1:3000/index")
39-
res["Content-Length"]
40-
`, "15"},
39+
res["X-Request-Method"]
40+
`, "HEAD"},
41+
{`
42+
require "net/http"
43+
44+
res = Net::HTTP.delete("http://127.0.0.1:3000/index")
45+
res["X-Request-Method"]
46+
`, "DELETE"},
47+
{`
48+
require "net/http"
49+
50+
res = Net::HTTP.options("http://127.0.0.1:3000/index")
51+
res["X-Request-Method"]
52+
`, "OPTIONS"},
4153
}
4254

4355
//block until server is ready
@@ -159,6 +171,7 @@ func startTestServer(c chan bool) {
159171
m := http.NewServeMux()
160172

161173
m.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
174+
w.Header().Set("X-Request-Method", r.Method)
162175
w.WriteHeader(http.StatusOK)
163176

164177
if r.Method == http.MethodPost {
@@ -168,7 +181,7 @@ func startTestServer(c chan bool) {
168181
}
169182
fmt.Fprintf(w, "POST %s", b)
170183
} else {
171-
fmt.Fprint(w, "GET Hello World")
184+
fmt.Fprintf(w, "%s Hello World", r.Method)
172185
}
173186

174187
})

0 commit comments

Comments
 (0)