better_rest 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +33 -0
- data/better_rest.gemspec +13 -0
- data/bin/better_rest +6 -0
- data/lib/better_rest.rb +107 -0
- data/logs/.DS_Store +0 -0
- data/public/favicon.ico +0 -0
- data/public/mainCSS.css +257 -0
- data/views/index.erb +389 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: be05ac41c0052a1ab680d43e0d6584e5c6375052
|
4
|
+
data.tar.gz: 03700925f50f7a8cfd4a53b009920c8be07208de
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ede9688f250b61a2e6cbf949daa84c6ac3ba38bae201c52880da00c43863815305eb91cced2fbc94b939e183b2f847f1bc17eb16caa2b6c281857cae79a819a9
|
7
|
+
data.tar.gz: c08b691f34aaebc7ed45f535cf2dd06af813c54865b08fb614eed91c0c886d14e2ecdfe3d0f10db4528926239905b3e7fa168d375bfd9c5dabb1373db5049999
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Jason Willems
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# BetteR
|
2
|
+
|
3
|
+
BetteR is a a REST testing client written in Ruby and served by Sinatra.
|
4
|
+
|
5
|
+
BetteR emphasises both a clean and easy to use interface, as well as allowing users to have a very granuler control over their requests (things like following redirects, verbosity of response, timeout intervals are all configurable). The current feature set is modest, but what it does, it aims to do well.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
$cd BetteR
|
10
|
+
$./BetteR
|
11
|
+
|
12
|
+
BetteR will run rest.rb, which will content to a Sinatra session via your browser (browser should launch automatically, but otherwise the default location is localhost:5678)
|
13
|
+
|
14
|
+
Logs (if enabled from the Settings menu in the UI) will be stored in the following location
|
15
|
+
|
16
|
+
./logs/YYYY-MM-DD.log
|
17
|
+
|
18
|
+
## Dependencies
|
19
|
+
|
20
|
+
Requires a ruby installation with the following Gems:
|
21
|
+
- 'sinatra' (sudo gem install sinatra)
|
22
|
+
- 'typhoeus' (sudo gem install typhoeus)
|
23
|
+
- 'vegas' (sudo gem install vegas)
|
24
|
+
|
25
|
+
Note that the vegas gem is only necessary in order to use ./BetteR to call rest.rb. Launching rest.rb (via 'ruby rest.rb') will avoid the need for this gem.
|
26
|
+
|
27
|
+
## TODO
|
28
|
+
|
29
|
+
* Add OAuth/OAuth2 support
|
30
|
+
* Update current deprecated Basic/Digest Auth method
|
31
|
+
* Add ability to save requests
|
32
|
+
* Add download to file
|
33
|
+
* Add parallel requests
|
data/better_rest.gemspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "better_rest"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.licenses = ['MIT']
|
5
|
+
s.summary = "REST test Client"
|
6
|
+
s.date = "2014-03-30"
|
7
|
+
s.description = "This is a REST API test client accessible via the browser."
|
8
|
+
s.authors = ["Jason Willems"]
|
9
|
+
s.email = ["hello@jasonwillems.com"]
|
10
|
+
s.homepage = "http://www.jasonwillems.com"
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.executables << 'better_rest'
|
13
|
+
end
|
data/bin/better_rest
ADDED
data/lib/better_rest.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'sinatra'
|
4
|
+
require 'typhoeus'
|
5
|
+
|
6
|
+
helpers do
|
7
|
+
include Rack::Utils
|
8
|
+
alias_method :h, :escape_html
|
9
|
+
end
|
10
|
+
|
11
|
+
get '/?' do
|
12
|
+
@requests = ["GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"]
|
13
|
+
@timeout = ["1","2","5","10","60"]
|
14
|
+
@validHeaderCount = 1
|
15
|
+
@headerHash = {"" => ""}
|
16
|
+
@follow, @verbose, @ssl, @loggingOn = true, true, false, false
|
17
|
+
@visible = ["displayed", "hidden", "displayed", "displayed", "displayed"] #Ordered display toggle for frontend: REQUEST, AUTH, HEADERS, PAYLOAD, RESULTS
|
18
|
+
erb :index
|
19
|
+
end
|
20
|
+
|
21
|
+
get '/env' do
|
22
|
+
<<-ENDRESPONSE
|
23
|
+
Ruby: #{RUBY_VERSION} <br/>
|
24
|
+
Rack: #{Rack::VERSION} <br/>
|
25
|
+
Sinatra: #{Sinatra::VERSION}
|
26
|
+
ENDRESPONSE
|
27
|
+
end
|
28
|
+
|
29
|
+
post '/' do
|
30
|
+
@headerHash = {}
|
31
|
+
@validHeaderCount = 1
|
32
|
+
@formResponse = true
|
33
|
+
@follow, @verbose, @ssl, @loggingOn = true, true, false, false
|
34
|
+
@requestBody = ""
|
35
|
+
@visible = [params[:serveURLDiv], params[:serveAuthDiv], params[:serveHeaderDiv], params[:servePayloadDiv], params[:serveResultsDiv]]
|
36
|
+
|
37
|
+
(0..Integer(params[:headerCount])).each do |i|
|
38
|
+
@keyIncrement = "key" + "#{i}"
|
39
|
+
@valueIncrement = "value" + "#{i}"
|
40
|
+
|
41
|
+
if params[@keyIncrement] and not params[@keyIncrement].empty? and params[@valueIncrement] and not params[@valueIncrement].empty?
|
42
|
+
@headerHash[params[@keyIncrement]] = params[@valueIncrement]
|
43
|
+
@validHeaderCount += 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if @headerHash["User-Agent"] == nil #add branded User-Agent header, only if empty
|
48
|
+
@headerHash["User-Agent"] = "BetteR - https://github.com/at1as/BetteR"
|
49
|
+
end
|
50
|
+
|
51
|
+
if params[:followlocation] == ""
|
52
|
+
@follow = false
|
53
|
+
end
|
54
|
+
if params[:verbose] == ""
|
55
|
+
@verbose = false
|
56
|
+
end
|
57
|
+
if params[:ssl_verifypeer] == "on"
|
58
|
+
@ssl = true
|
59
|
+
end
|
60
|
+
if params[:enableLogging] == "on"
|
61
|
+
@loggingOn = true
|
62
|
+
end
|
63
|
+
unless params[:datafile].nil?
|
64
|
+
@requestBody = { content: params[:payload], file: File.open(params[:datafile][:tempfile], 'r') }
|
65
|
+
else
|
66
|
+
@requestBody = { content: params[:payload] }
|
67
|
+
end
|
68
|
+
|
69
|
+
request = Typhoeus::Request.new(
|
70
|
+
params[:url],
|
71
|
+
method: params[:requestType],
|
72
|
+
:username => params[:usr],
|
73
|
+
:password => params[:pwd],
|
74
|
+
:auth_method => :auto, #Should be manually set in order to test unideal APIs
|
75
|
+
:headers => @headerHash,
|
76
|
+
:body => @requestBody, #to replace -> body: params[:payload],
|
77
|
+
followlocation: @follow,
|
78
|
+
verbose: @verbose,
|
79
|
+
ssl_verifypeer: @ssl,
|
80
|
+
:timeout => Integer(params[:timeoutInterval])
|
81
|
+
)
|
82
|
+
|
83
|
+
request.run
|
84
|
+
response = request.response
|
85
|
+
|
86
|
+
if @headerHash["User-Agent"] == "BetteR - https://github.com/at1as/BetteR"
|
87
|
+
@headerHash.delete("User-Agent")
|
88
|
+
end
|
89
|
+
|
90
|
+
if @loggingOn == true
|
91
|
+
File.open('log/' + Time.now.strftime("%Y-%m-%d") + '.log', 'a') {
|
92
|
+
|file| file.write("-"*10 + "\n" + Time.now.to_s + request.inspect + "\n\n" )
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
puts params[:payload]
|
97
|
+
|
98
|
+
@requestOptions = request.options
|
99
|
+
@returnBody = response.body
|
100
|
+
@returnCode = response.return_code
|
101
|
+
@returnTime = response.time
|
102
|
+
@statCodeReturn = response.response_headers
|
103
|
+
|
104
|
+
@requests = ["#{params[:requestType]}", "GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"].uniq
|
105
|
+
@timeout = ["1","2","5","10","60"]
|
106
|
+
erb :index
|
107
|
+
end
|
data/logs/.DS_Store
ADDED
Binary file
|
data/public/favicon.ico
ADDED
Binary file
|
data/public/mainCSS.css
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
body {
|
2
|
+
font-family:"Gill Sans", "Gill Sans MT", Sans-Serif;
|
3
|
+
background-color: #FDFDFD;
|
4
|
+
padding-bottom: 20px;
|
5
|
+
margin: 0px;
|
6
|
+
}
|
7
|
+
.container{
|
8
|
+
width: 555px;
|
9
|
+
margin:10px auto 0px auto;
|
10
|
+
}
|
11
|
+
.forceInline{
|
12
|
+
display:inline;
|
13
|
+
}
|
14
|
+
.backgroundText{
|
15
|
+
text-align: center;
|
16
|
+
color:#888888;
|
17
|
+
}
|
18
|
+
|
19
|
+
.width25{
|
20
|
+
width:13%;
|
21
|
+
padding:0px;
|
22
|
+
}
|
23
|
+
.widthRemainder{
|
24
|
+
display: inline;
|
25
|
+
width: 78%;
|
26
|
+
border: 2px 2px 2px 2px;
|
27
|
+
border-radius: 2px;
|
28
|
+
background-color:#FDFDFD;
|
29
|
+
}
|
30
|
+
.restrictedHeight{
|
31
|
+
padding: 10px 4px 10px 4px;
|
32
|
+
max-height: 200px;
|
33
|
+
overflow: scroll;
|
34
|
+
background-color: #F2F2F2;
|
35
|
+
border-radius: 3px;
|
36
|
+
}
|
37
|
+
.close {
|
38
|
+
display: inline;
|
39
|
+
font-size: 12px;
|
40
|
+
font-weight: bold;
|
41
|
+
color: #555555;
|
42
|
+
margin-left: 4px;
|
43
|
+
padding-left: 2px;
|
44
|
+
padding-right: 2px;
|
45
|
+
vertical-align: center;
|
46
|
+
}
|
47
|
+
.close:hover{
|
48
|
+
color:red;
|
49
|
+
border-radius: 7px;
|
50
|
+
background-color: #CCCCCC;
|
51
|
+
}
|
52
|
+
|
53
|
+
.minimal{
|
54
|
+
padding:0px;
|
55
|
+
}
|
56
|
+
.box{
|
57
|
+
padding:5px 5px 5px 5px;
|
58
|
+
background: linear-gradient(to bottom right, #F7F7F7, #F5F5F5, #F3F3F3);
|
59
|
+
border-radius: 4px;
|
60
|
+
border-style: solid;
|
61
|
+
border-color: #CFCFCF;
|
62
|
+
border-width: 1px;
|
63
|
+
transition: 90s;
|
64
|
+
box-shadow: 2px 1px 1px #CCCCCC;
|
65
|
+
|
66
|
+
}
|
67
|
+
.minmax:hover{
|
68
|
+
color:black;
|
69
|
+
}
|
70
|
+
h1 {
|
71
|
+
font-size: 14px;
|
72
|
+
color: #999999;
|
73
|
+
font-style: normal;
|
74
|
+
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
75
|
+
}
|
76
|
+
h2 {
|
77
|
+
font-size: 15px;
|
78
|
+
color: red;
|
79
|
+
display: inline-block;
|
80
|
+
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
81
|
+
/*padding: 12px 0 0px 0;*/
|
82
|
+
}
|
83
|
+
.holdValue {
|
84
|
+
transition: 0s 9999999s;
|
85
|
+
}
|
86
|
+
div:active {
|
87
|
+
transition:90s;
|
88
|
+
}
|
89
|
+
|
90
|
+
#submit {
|
91
|
+
border:none;
|
92
|
+
background:#888888;
|
93
|
+
margin-top: 8px;
|
94
|
+
padding: 4px 12px 4px 12px;
|
95
|
+
border-radius: 3px;
|
96
|
+
color: white;
|
97
|
+
float: right;
|
98
|
+
margin-left: 10px;
|
99
|
+
box-shadow: 2px 2px 1px #DDDDDD;
|
100
|
+
}
|
101
|
+
#submit:hover{
|
102
|
+
color:black;
|
103
|
+
}
|
104
|
+
#clearBtn{
|
105
|
+
border:none;
|
106
|
+
background:#ff4b33;
|
107
|
+
margin-top: 8px;
|
108
|
+
padding: 4px 12px 4px 12px;
|
109
|
+
border-radius: 3px;
|
110
|
+
font-weight: bold;
|
111
|
+
color: white;
|
112
|
+
float: right;
|
113
|
+
margin-left: 10px;
|
114
|
+
box-shadow: 2px 2px 1px #DDDDDD;
|
115
|
+
}
|
116
|
+
#clearBtn:hover{
|
117
|
+
color:black;
|
118
|
+
}
|
119
|
+
#variables{
|
120
|
+
border:none;
|
121
|
+
background:#ff4b33;
|
122
|
+
margin-top: 8px;
|
123
|
+
padding: 4px 12px 4px 12px;
|
124
|
+
border-radius: 3px;
|
125
|
+
font-weight: bold;
|
126
|
+
color: white;
|
127
|
+
float: right;
|
128
|
+
margin-left: 10px;
|
129
|
+
box-shadow: 2px 2px 1px #DDDDDD;
|
130
|
+
}
|
131
|
+
#variables:hover{
|
132
|
+
color:black;
|
133
|
+
}
|
134
|
+
input{
|
135
|
+
width:46%;
|
136
|
+
border-radius: 2px;
|
137
|
+
background-color:#FEFEFE;
|
138
|
+
border-color: transparent;
|
139
|
+
box-shadow: 2px 1px 1px #DDDDDD;
|
140
|
+
font-family: Arial;
|
141
|
+
font-size: 13px;
|
142
|
+
}
|
143
|
+
textarea{
|
144
|
+
border-radius: 4px;
|
145
|
+
border-color: transparent;
|
146
|
+
background-color: #FDFDFD;
|
147
|
+
overflow:hidden;
|
148
|
+
min-height: 80px;
|
149
|
+
max-width: 98%;
|
150
|
+
min-width: 98%;
|
151
|
+
box-shadow: 2px 1px 1px #DDDDDD;
|
152
|
+
font-family: arial;
|
153
|
+
font-size: 13px;
|
154
|
+
}
|
155
|
+
|
156
|
+
#add{
|
157
|
+
color:white;
|
158
|
+
background-color: #B9B9B9;
|
159
|
+
margin-top: 3px;
|
160
|
+
width:90px;
|
161
|
+
}
|
162
|
+
#add:hover{
|
163
|
+
color:black;
|
164
|
+
}
|
165
|
+
#add:active{
|
166
|
+
color: red;
|
167
|
+
}
|
168
|
+
#dialog-modal{
|
169
|
+
visibility: none;
|
170
|
+
}
|
171
|
+
ul{
|
172
|
+
margin: 5px 5px 0px 5px;
|
173
|
+
padding: 0;
|
174
|
+
text-align: left;
|
175
|
+
|
176
|
+
}
|
177
|
+
li {
|
178
|
+
min-width: 200px;
|
179
|
+
}
|
180
|
+
li a{
|
181
|
+
text-decoration: none;
|
182
|
+
text-align: left;
|
183
|
+
padding-right: 20px;
|
184
|
+
padding-top: 2px;
|
185
|
+
padding-bottom: 2px;
|
186
|
+
padding-left: 20px;
|
187
|
+
margin-right: 10px;
|
188
|
+
border-radius: 3px;
|
189
|
+
background-color: #B9B9B9;
|
190
|
+
font-size: 12px;
|
191
|
+
color: #FFFFFF;
|
192
|
+
font-weight: normal;
|
193
|
+
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
194
|
+
}
|
195
|
+
|
196
|
+
li a:hover{
|
197
|
+
color:black;
|
198
|
+
}
|
199
|
+
.resultsBoxHead {
|
200
|
+
visibility: none;
|
201
|
+
}
|
202
|
+
.resultsBoxcURL {
|
203
|
+
visibility: none;
|
204
|
+
}
|
205
|
+
#dialog-background-blur{
|
206
|
+
background-color: #EEEEEE;
|
207
|
+
opacity: 0.85;
|
208
|
+
position: fixed;
|
209
|
+
left:0;
|
210
|
+
top:0;
|
211
|
+
width:100%;
|
212
|
+
height:100%;
|
213
|
+
z-index: 10;
|
214
|
+
}
|
215
|
+
|
216
|
+
#load-dialog-modal{
|
217
|
+
background-color: #CCCCCC;
|
218
|
+
opacity:1.0;
|
219
|
+
position: fixed;
|
220
|
+
top: 25%;
|
221
|
+
left: 50% ;
|
222
|
+
width:280px;
|
223
|
+
margin-left:-140px;
|
224
|
+
padding:20px;
|
225
|
+
box-shadow: 2px 1px 1px #DDDDDD;
|
226
|
+
z-index:11;
|
227
|
+
}
|
228
|
+
|
229
|
+
#file-upload-modal {
|
230
|
+
background-color: #CCCCCC;
|
231
|
+
opacity:1.0;
|
232
|
+
position: fixed;
|
233
|
+
top: 25%;
|
234
|
+
left: 50% ;
|
235
|
+
width:280px;
|
236
|
+
margin-left:-140px;
|
237
|
+
padding:20px;
|
238
|
+
box-shadow: 2px 1px 1px #DDDDDD;
|
239
|
+
z-index:11;
|
240
|
+
}
|
241
|
+
|
242
|
+
#header{
|
243
|
+
background-color:black;
|
244
|
+
color:white;
|
245
|
+
padding-top:3px;
|
246
|
+
padding-bottom:3px;
|
247
|
+
}
|
248
|
+
|
249
|
+
#settingsbutton {
|
250
|
+
color:#999999;
|
251
|
+
background-color: #000000;
|
252
|
+
}
|
253
|
+
|
254
|
+
label {
|
255
|
+
font-family: "Helvetica";
|
256
|
+
font-size:14px;
|
257
|
+
}
|
data/views/index.erb
ADDED
@@ -0,0 +1,389 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>BetteR — A REST API Testing Utility</title>
|
6
|
+
<link rel="shortcut icon" href="favicon.ico">
|
7
|
+
<link rel="stylesheet" href="mainCSS.css">
|
8
|
+
</head>
|
9
|
+
|
10
|
+
<body>
|
11
|
+
<div id="header">
|
12
|
+
<div class="container" style="margin:0px auto 0px auto;">
|
13
|
+
<div id="header-title" style="display:inline-block">
|
14
|
+
<h1 style="min-width:100%;">BetteR — A REST API Testing Utility.</h1>
|
15
|
+
</div>
|
16
|
+
<div style="display:inline-block; float:right; margin-left:10px;">
|
17
|
+
<div id="settings-button" onclick="modalToggle('load-dialog-modal')" style="height:100%; margin-top:8px; display:inline-block">Settings</div>
|
18
|
+
</div>
|
19
|
+
<div style="display:inline-block; float:right; margin-right:10px;">
|
20
|
+
<div id="file-upload-button" onclick="modalToggle('file-upload-modal')" style="height:100%; margin-top:8px; display:inline-block">File Upload</div>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<div class="container">
|
25
|
+
<form id="form1" name="fullRequestData" method="post" action="/" target="_self" enctype="multipart/form-data">
|
26
|
+
<div>
|
27
|
+
<% if @visible[0] == "hidden"%>
|
28
|
+
<input type="hidden" id="serveURLDiv" name="serveURLDiv" value="hidden">
|
29
|
+
<% else %>
|
30
|
+
<input type="hidden" id="serveURLDiv" name="serveURLDiv" value="displayed">
|
31
|
+
<% end %>
|
32
|
+
<h2><div class="head" id="headingReq" onclick="toggleRequestVisibility()">[–] Request</div></h2>
|
33
|
+
<div class="box" id="path">
|
34
|
+
<select id="requestType" name="requestType">
|
35
|
+
<% @requests.each do |request| %>
|
36
|
+
<option value=<%= request %>><%= request %></option>
|
37
|
+
<% end %>
|
38
|
+
</select>
|
39
|
+
<input type="text" value="<%= h(params[:url]) %>" name="url" id="url" placeholder=" URL" class="widthRemainder"/>
|
40
|
+
<div class="close" id="closeURL" onclick="clearURL()">X</div>
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
<div>
|
44
|
+
<% if @visible[1] == "hidden"%>
|
45
|
+
<input type="hidden" id="serveAuthDiv" name="serveAuthDiv" value="hidden">
|
46
|
+
<% else %>
|
47
|
+
<input type="hidden" id="serveAuthDiv" name="serveAuthDiv" value="displayed">
|
48
|
+
<% end %>
|
49
|
+
<h2><div class="head" id="headingAuth" onclick="toggleAuthVisibility()">[–] Authentication</div></h2>
|
50
|
+
<div class="box" id="auth">
|
51
|
+
<div id="authSelect">
|
52
|
+
<span style="display:inline-block; white-space:nowrap; margin-top:5px;margin-bottom:5px;">
|
53
|
+
<label for="basicAuthSelect">
|
54
|
+
<input id="basicAuthSelect" type="radio" name="authType" value="basic" checked="true" style="width:14px;">Basic
|
55
|
+
</label>
|
56
|
+
<label for="digestAuthSelect">
|
57
|
+
<input id="digestAuthSelect" type="radio" name="authType" value="digest" style="width:14px;">Digest
|
58
|
+
</label>
|
59
|
+
</span>
|
60
|
+
</div>
|
61
|
+
<input type="text" value="<%=h(params[:usr])%>" name="usr" id="usr" placeholder=" Username" />
|
62
|
+
<input type="text" value="<%=h(params[:pwd])%>" name="pwd" id="pwd" placeholder=" Password" />
|
63
|
+
<div class="close" id="closeAuth" onclick="clearAuthCredentials()">X</div>
|
64
|
+
</div>
|
65
|
+
</div>
|
66
|
+
<div>
|
67
|
+
<% if @visible[2] == "hidden"%>
|
68
|
+
<input type="hidden" id="serveHeaderDiv" name="serveHeaderDiv" value="hidden">
|
69
|
+
<% else %>
|
70
|
+
<input type="hidden" id="serveHeaderDiv" name="serveHeaderDiv" value="displayed">
|
71
|
+
<% end %>
|
72
|
+
<input type="hidden" id="headerCount" name="headerCount" value="1">
|
73
|
+
<h2><div class="head" id="headingHead" onclick="toggleHeaderVisibility()">[–] Headers</div></h2>
|
74
|
+
<div class="box" id="headers">
|
75
|
+
<div id="headerfieldsAll">
|
76
|
+
<% @headerHash.each_with_index do |(key, value), index| %>
|
77
|
+
<div id="headerfields<%= index %>" style="margin-bottom:2px;" >
|
78
|
+
<input type="text" value="<%=key%>" name="key<%=index%>" id="key<%=index%>" placeholder=" Name" class="key" />
|
79
|
+
<input type="text" value="<%=value%>" name="value<%=index%>" id="value<%=index%>" placeholder=" Value" class="value" />
|
80
|
+
<div class="close" id="close<%= index %>" onclick="removeRow(this)">X</div>
|
81
|
+
</div>
|
82
|
+
<% end %>
|
83
|
+
</div>
|
84
|
+
<div>
|
85
|
+
<input type="button" value="Add<%=h(params[:add])%>" id="add" class="width25" onclick="addNewHeader()"/>
|
86
|
+
</div>
|
87
|
+
</div>
|
88
|
+
</div>
|
89
|
+
<div>
|
90
|
+
<% if @visible[3] == "hidden"%>
|
91
|
+
<input type="hidden" id="servePayloadDiv" name="servePayloadDiv" value="hidden">
|
92
|
+
<% else %>
|
93
|
+
<input type="hidden" id="servePayloadDiv" name="servePayloadDiv" value="displayed">
|
94
|
+
<% end %>
|
95
|
+
<h2><div class="head" id="headingData" onclick="toggleDataVisibility()">[–] Payload</div></h2>
|
96
|
+
<div class="box" id="data">
|
97
|
+
<textarea value="<%=h(params[:payload])%>" name="payload" id="payload" placeholder=" Payload Data"><%=h(params[:payload])%></textarea>
|
98
|
+
</div>
|
99
|
+
</div>
|
100
|
+
<div style="margin-top:5px, padding-top: 3px, padding-bottom: 4px">
|
101
|
+
<input type="submit" value="Send" id="submit" class="width25" onclick="prepareSubmission()" style="margin-bottom:10px;"/>
|
102
|
+
<input type="button" value="Clear All" id="submit" class="width25" onclick="clearAllFields()" style="margin-bottom:10px;"/>
|
103
|
+
</div>
|
104
|
+
<% if @formResponse == true %>
|
105
|
+
<div>
|
106
|
+
<% if @visible[4] == "hidden"%>
|
107
|
+
<input type="hidden" id="serveResultsDiv" name="serveResultsDiv" value="hidden">
|
108
|
+
<% else %>
|
109
|
+
<input type="hidden" id="serveResultsDiv" name="serveResultsDiv" value="displayed">
|
110
|
+
<% end %>
|
111
|
+
<h2><div class="head" id="headingResults" style="margin-top:10px" onclick="toggleResultsVisibility()">[–] Results</div></h2>
|
112
|
+
<div class="box" id="results">
|
113
|
+
<ul>
|
114
|
+
<li style="display:inline;" id="viewResponseTab">
|
115
|
+
<a onclick="hideReq()" id="responseDataText" style="color:#000000">Response Data</a>
|
116
|
+
</li>
|
117
|
+
<li style="display:inline" id="viewResponseHeadersTab">
|
118
|
+
<a onclick="hideRespData()"id="responseHeaderText">Response Headers</a>
|
119
|
+
</li>
|
120
|
+
<li style="display:inline" id="viewRequestTab">
|
121
|
+
<a onclick="hideResp()" id="requestHeaderText">Request Body</a>
|
122
|
+
</li>
|
123
|
+
</ul>
|
124
|
+
<div >
|
125
|
+
<textarea style="min-height:180px; margin-top:10px; overflow:scroll" id="resultsBox"><%= @returnBody.to_s %>
|
126
|
+

----
Response: <%= @returnCode.to_s %> 
Request Time: <%= @returnTime.to_s %> seconds
|
127
|
+
</textarea>
|
128
|
+
<textarea style="min-height:180px; margin-top:10px; overflow:scroll; display:none" id="resultsBoxHead"><%= @statCodeReturn.to_s %></textarea>
|
129
|
+
<textarea style="min-height:180px; margin-top:10px; overflow:scroll; display:none" id="resultsBoxcURL"><%= @requestOptions.to_s %></textarea>
|
130
|
+
</div>
|
131
|
+
</div>
|
132
|
+
</div>
|
133
|
+
<% end %>
|
134
|
+
<!-- MODAL GRAY BACKGROUND -->
|
135
|
+
<div id="dialog-background-blur" style="visibility:hidden" onclick="modalHideAll()"></div>
|
136
|
+
<!-- BEGIN SETTINGS MODAL-->
|
137
|
+
<div id="load-dialog-modal" title="Settings" style="border-radius:4px; visibility:hidden" onclick="returnFalse(event)">
|
138
|
+
<p style="font-size:15px; margin-top:0px"><strong>Configuration:</strong></p>
|
139
|
+
<div style="display:inline-block;width:100%">
|
140
|
+
<label for="followlocation">
|
141
|
+
<input type="checkbox" name="followlocation" id="followlocation" style="float:right"
|
142
|
+
<% if @follow == true %>checked<% end %>>
|
143
|
+
Follow Redirects?<br/>
|
144
|
+
</label>
|
145
|
+
<label for="verbose">
|
146
|
+
<input type="checkbox" name="verbose" id="verbose" style="float:right"
|
147
|
+
<% if @verbose == true %>checked<% end %>>
|
148
|
+
Verbose Response?<br/>
|
149
|
+
</label>
|
150
|
+
<label for="ssl_verifypeer">
|
151
|
+
<input type="checkbox" name="ssl_verifypeer" id="ssl_verifypeer" style="float:right"
|
152
|
+
<% if @ssl == true %>checked<% end %>>
|
153
|
+
Verify SSL Peers?<br/>
|
154
|
+
</label>
|
155
|
+
<label for="enableLogging">
|
156
|
+
<input type="checkbox" name="enableLogging" id="enableLogging" style="float:right"
|
157
|
+
<% if @loggingOn == true %>checked<% end %>>
|
158
|
+
Log Requests?<br/>
|
159
|
+
</label>
|
160
|
+
<label for="timeoutInterval">
|
161
|
+
<select id="timeoutInterval" name="timeoutInterval" style="float:right">
|
162
|
+
<% @timeout.each do |interval| %>
|
163
|
+
<option value=<%= interval %>
|
164
|
+
<% if h(params[:timeoutInterval]) == interval%>selected<% end %> ><%= interval %>
|
165
|
+
</option>
|
166
|
+
<% end %>
|
167
|
+
</select>
|
168
|
+
<span style="margin-right:30px;">Timeout Inteval:</span>
|
169
|
+
</label>
|
170
|
+
</div>
|
171
|
+
</div>
|
172
|
+
<!-- END SETTINGS MODAL -->
|
173
|
+
<!-- BEGIN FILE UPLOAD MODAL -->
|
174
|
+
<!--<div id="dialog-background-blur" style="visibility:hidden" onclick="modalToggle('file-upload-modal')">-->
|
175
|
+
<div id="file-upload-modal" title="File Upload" style="border-radius:4px; visibility:hidden" onclick="returnFalse(event)">
|
176
|
+
<p style="font-size:15px; margin-top:0px"><strong>Attach File to Request:</strong></p>
|
177
|
+
<div>
|
178
|
+
<input type="file" id="datafile" name="datafile" style="width:100%; background-color:#CCCCCC; box-shadow:none;">
|
179
|
+
</div>
|
180
|
+
<div style="margin-top:10px;">
|
181
|
+
<input type="button" value=" OK" onclick="modalToggle('file-upload-modal')">
|
182
|
+
</div>
|
183
|
+
</div>
|
184
|
+
<!--</div> -->
|
185
|
+
<!-- END FILE UPLOAD MODAL -->
|
186
|
+
</form>
|
187
|
+
</div>
|
188
|
+
|
189
|
+
<script type="text/javascript" >
|
190
|
+
|
191
|
+
/*Toggle Modal display on page*/
|
192
|
+
function modalToggle(modal_id) {
|
193
|
+
bgrnd = document.getElementById("dialog-background-blur");
|
194
|
+
bgrnd.style.visibility = (bgrnd.style.visibility == "visible") ? "hidden" : "visible";
|
195
|
+
el = document.getElementById(modal_id);
|
196
|
+
el.style.visibility = (el.style.visibility == "visible") ? "hidden" : "visible";
|
197
|
+
}
|
198
|
+
|
199
|
+
function modalHideAll() {
|
200
|
+
document.getElementById("dialog-background-blur").style.visibility = "hidden";
|
201
|
+
document.getElementById("load-dialog-modal").style.visibility = "hidden";
|
202
|
+
document.getElementById("file-upload-modal").style.visibility = "hidden";
|
203
|
+
}
|
204
|
+
|
205
|
+
/*Re-serve minimised sections minimised on page reload. Note data from fields is always submitted*/
|
206
|
+
if (document.getElementById("serveURLDiv").value == "hidden") {
|
207
|
+
toggleRequestVisibility("arg1");
|
208
|
+
}
|
209
|
+
if (document.getElementById("serveAuthDiv").value == "hidden") {
|
210
|
+
toggleAuthVisibility("arg1");
|
211
|
+
}
|
212
|
+
if (document.getElementById("serveHeaderDiv").value == "hidden") {
|
213
|
+
toggleHeaderVisibility("arg1");
|
214
|
+
}
|
215
|
+
if (document.getElementById("servePayloadDiv").value == "hidden") {
|
216
|
+
toggleDataVisibility("arg1");
|
217
|
+
}
|
218
|
+
if (document.getElementById("serveResultsDiv") && document.getElementById("serveResultsDiv").value == "hidden") {
|
219
|
+
toggleResultsVisibility("arg1");
|
220
|
+
}
|
221
|
+
|
222
|
+
/*Change page layout to reflect minimizing/maximising divs*/
|
223
|
+
function toggleRequestVisibility(){
|
224
|
+
document.getElementById("path").style.display = (document.getElementById("path").style.display != 'none' ? 'none' : '');
|
225
|
+
document.getElementById("headingReq").innerHTML = (document.getElementById("path").style.display != 'none' ? "[–] Request" : "[+] Request");
|
226
|
+
document.getElementById("headingReq").style.color = (document.getElementById("path").style.display != 'none' ? "red" : "#BBBBBB");
|
227
|
+
document.getElementById("headingReq").style.margin = (document.getElementById("path").style.display != 'none' ? "0px 0px 0px" : "0px 0px -20px");
|
228
|
+
//So we can block this from being executed on page reload, which would undo the minimise
|
229
|
+
if (arguments.length == 0) {
|
230
|
+
document.getElementById("serveURLDiv").value = (document.getElementById("serveURLDiv").value != 'hidden' ? 'hidden' : 'displayed');
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
function toggleAuthVisibility(){
|
235
|
+
document.getElementById("auth").style.display = (document.getElementById("auth").style.display != 'none' ? 'none' : '');
|
236
|
+
document.getElementById("headingAuth").innerHTML = (document.getElementById("auth").style.display != 'none' ? "[–] Authentication" : "[+] Authentication");
|
237
|
+
document.getElementById("headingAuth").style.color = (document.getElementById("auth").style.display != 'none' ? "red" : "#BBBBBB");
|
238
|
+
document.getElementById("headingAuth").style.margin = (document.getElementById("auth").style.display != 'none' ? "0px 0px 0px" : "0px 0px -20px");
|
239
|
+
if (arguments.length == 0 ) {
|
240
|
+
document.getElementById("serveAuthDiv").value = (document.getElementById("serveAuthDiv").value != 'hidden' ? 'hidden' : 'displayed');
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
function toggleHeaderVisibility(){
|
245
|
+
document.getElementById("headers").style.display = (document.getElementById("headers").style.display != 'none' ? 'none' : '');
|
246
|
+
document.getElementById("headingHead").innerHTML = (document.getElementById("headers").style.display != 'none' ? "[–] Headers" : "[+] Headers");
|
247
|
+
document.getElementById("headingHead").style.color = (document.getElementById("headers").style.display != 'none' ? "red" : "#BBBBBB");
|
248
|
+
document.getElementById("headingHead").style.margin = (document.getElementById("headers").style.display != 'none' ? "0px 0px 0px" : "0px 0px -20px");
|
249
|
+
if (arguments.length == 0 ) {
|
250
|
+
document.getElementById("serveHeaderDiv").value = (document.getElementById("serveHeaderDiv").value != 'hidden' ? 'hidden' : 'displayed');
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
function toggleDataVisibility(){
|
255
|
+
document.getElementById("data").style.display = (document.getElementById("data").style.display != 'none' ? 'none' : '');
|
256
|
+
document.getElementById("headingData").innerHTML = (document.getElementById("data").style.display != 'none' ? "[–] Payload" : "[+] Payload");
|
257
|
+
document.getElementById("headingData").style.color = (document.getElementById("data").style.display != 'none' ? "red" : "#BBBBBB");
|
258
|
+
document.getElementById("headingData").style.margin = (document.getElementById("data").style.display != 'none' ? "0px 0px 0px" : "0px 0px -20px");
|
259
|
+
if (arguments.length == 0) {
|
260
|
+
document.getElementById("servePayloadDiv").value = (document.getElementById("servePayloadDiv").value != 'hidden' ? 'hidden' : 'displayed');
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
function toggleResultsVisibility() {
|
265
|
+
document.getElementById("results").style.display = (document.getElementById("results").style.display != 'none' ? 'none' : '');
|
266
|
+
document.getElementById("headingResults").innerHTML = (document.getElementById("results").style.display != 'none' ? "[–] Results" : "[+] Results");
|
267
|
+
document.getElementById("headingResults").style.color = (document.getElementById("results").style.display != 'none' ? "red" : "#BBBBBB");
|
268
|
+
document.getElementById("headingResults").style.margin = (document.getElementById("results").style.display != 'none' ? "10px 0px 0px" : "10px 0px -20px");
|
269
|
+
if (arguments.length == 0) {
|
270
|
+
document.getElementById("serveResultsDiv").value = (document.getElementById("serveResultsDiv").value != 'hidden' ? 'hidden' : 'displayed');
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
/*clear all form fields. Delete additional header fields*/
|
275
|
+
function clearAllFields() {
|
276
|
+
document.getElementById("requestType").value = "GET";
|
277
|
+
document.getElementById("url").value = "";
|
278
|
+
document.getElementById("usr").value = "";
|
279
|
+
document.getElementById("pwd").value = "";
|
280
|
+
document.getElementById("payload").value = "";
|
281
|
+
if (document.getElementById("resultsBox")){
|
282
|
+
document.getElementById("resultsBox").value = "";
|
283
|
+
}
|
284
|
+
if (document.getElementById("resultsBoxHead")) {
|
285
|
+
document.getElementById("resultsBoxHead").value = "";
|
286
|
+
}
|
287
|
+
if (document.getElementById("resultsBoxcURL")) {
|
288
|
+
document.getElementById("resultsBoxcURL").value = "";
|
289
|
+
}
|
290
|
+
while (headerfieldsAll.firstChild) {
|
291
|
+
headerfieldsAll.removeChild(headerfieldsAll.firstChild);
|
292
|
+
}
|
293
|
+
}
|
294
|
+
|
295
|
+
var clickCount = document.getElementById('headerfieldsAll').children.length - 1;
|
296
|
+
document.getElementById("headerCount").value = clickCount + 1;
|
297
|
+
|
298
|
+
function addNewHeader() {
|
299
|
+
clickCount += 1;
|
300
|
+
document.getElementById("headerCount").value = clickCount + 1;
|
301
|
+
|
302
|
+
var input0 = document.createElement('div');
|
303
|
+
var input = document.createElement('input');
|
304
|
+
var input2 = document.createElement('input');
|
305
|
+
var input3 = document.createElement('div');
|
306
|
+
input0.type = "div";
|
307
|
+
input0.style = "margin-bottom:2px;"
|
308
|
+
input.type = "text";
|
309
|
+
input2.type = "text";
|
310
|
+
input3.type = "close";
|
311
|
+
input3.className = "close";
|
312
|
+
input.placeholder = " Name";
|
313
|
+
input2.placeholder = " Value";
|
314
|
+
input.id = "key" + clickCount;
|
315
|
+
input.className = "key";
|
316
|
+
input2.className = "value";
|
317
|
+
input.autocomplete = "off";
|
318
|
+
input3.id = "close" + clickCount;
|
319
|
+
input.style.margin = "0px 4px 0px 0px";
|
320
|
+
input3.style.margin = "0px 0px 0px 9px";
|
321
|
+
input2.id = "value" + clickCount;
|
322
|
+
input0.id = "headerfields" + clickCount;
|
323
|
+
input.name = "key" + clickCount;
|
324
|
+
input2.name = "value" + clickCount;
|
325
|
+
input.value = '<%=h(params[:key])%>';
|
326
|
+
input.value = input.value.replace('key', 'key' + clickCount);
|
327
|
+
|
328
|
+
input2.value = '<%=h(params[:value])%>';
|
329
|
+
input2.value = input2.value.replace('value', 'value' + clickCount);
|
330
|
+
input3.innerHTML = "X";
|
331
|
+
input3.setAttribute("onclick", "removeRow(this)");
|
332
|
+
|
333
|
+
document.getElementById('headerfieldsAll').appendChild(input0);
|
334
|
+
input0.appendChild(input);
|
335
|
+
input0.appendChild(input2);
|
336
|
+
input0.appendChild(input3);
|
337
|
+
document.getElementById(input.id).focus()
|
338
|
+
}
|
339
|
+
|
340
|
+
function clearAuthCredentials() {
|
341
|
+
document.getElementById('usr').value = '';
|
342
|
+
document.getElementById('pwd').value = '';
|
343
|
+
}
|
344
|
+
|
345
|
+
function clearURL(){
|
346
|
+
document.getElementById('url').value = '';
|
347
|
+
}
|
348
|
+
|
349
|
+
function removeRow(rowNumber) {
|
350
|
+
rNum = rowNumber.id.charAt(rowNumber.id.length -1);
|
351
|
+
document.getElementById('headerfieldsAll').removeChild(document.getElementById('headerfields' + rNum));
|
352
|
+
}
|
353
|
+
|
354
|
+
function hideReq() {
|
355
|
+
document.getElementById("resultsBox").style.display = '';
|
356
|
+
document.getElementById("responseDataText").style.color = "#000000";
|
357
|
+
document.getElementById("resultsBoxHead").style.display = 'none';
|
358
|
+
document.getElementById("responseHeaderText").style.color = "#FFFFFF";
|
359
|
+
document.getElementById("resultsBoxcURL").style.display = 'none';
|
360
|
+
document.getElementById("requestHeaderText").style.color = "#FFFFFF";
|
361
|
+
}
|
362
|
+
|
363
|
+
function hideRespData() {
|
364
|
+
document.getElementById("resultsBox").style.display = 'none';
|
365
|
+
document.getElementById("responseDataText").style.color = "#FFFFFF";
|
366
|
+
document.getElementById("resultsBoxHead").style.display = '';
|
367
|
+
document.getElementById("responseHeaderText").style.color = "#000000";
|
368
|
+
document.getElementById("resultsBoxcURL").style.display = 'none';
|
369
|
+
document.getElementById("requestHeaderText").style.color = "#FFFFFF";
|
370
|
+
}
|
371
|
+
|
372
|
+
function hideResp() {
|
373
|
+
document.getElementById("resultsBox").style.display = 'none';
|
374
|
+
document.getElementById("responseDataText").style.color = "#FFFFFF";
|
375
|
+
document.getElementById("resultsBoxHead").style.display = 'none';
|
376
|
+
document.getElementById("responseHeaderText").style.color = "#FFFFFF";
|
377
|
+
document.getElementById("resultsBoxcURL").style.display = '';
|
378
|
+
document.getElementById("requestHeaderText").style.color = "#000000";
|
379
|
+
}
|
380
|
+
|
381
|
+
/*Block some JS and Form behaviour from occuring*/
|
382
|
+
function returnFalse(event) {
|
383
|
+
event.cancelBubble=true;
|
384
|
+
if(event.stopPropagation) { event.stopPropagation(); }
|
385
|
+
return false;
|
386
|
+
}
|
387
|
+
</script>
|
388
|
+
</body>
|
389
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: better_rest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jason Willems
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-30 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: This is a REST API test client accessible via the browser.
|
14
|
+
email:
|
15
|
+
- hello@jasonwillems.com
|
16
|
+
executables:
|
17
|
+
- better_rest
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- LICENSE
|
22
|
+
- README.md
|
23
|
+
- better_rest.gemspec
|
24
|
+
- bin/better_rest
|
25
|
+
- lib/better_rest.rb
|
26
|
+
- logs/.DS_Store
|
27
|
+
- public/favicon.ico
|
28
|
+
- public/mainCSS.css
|
29
|
+
- views/index.erb
|
30
|
+
homepage: http://www.jasonwillems.com
|
31
|
+
licenses:
|
32
|
+
- MIT
|
33
|
+
metadata: {}
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 2.2.2
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: REST test Client
|
54
|
+
test_files: []
|