better_rest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.
@@ -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
@@ -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
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../lib/better_rest.rb')
4
+ require 'vegas'
5
+
6
+ Vegas::Runner.new(Sinatra::Application, 'rest')
@@ -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
Binary file
Binary file
@@ -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
+ }
@@ -0,0 +1,389 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>BetteR &mdash; 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 &mdash; 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()">[&ndash;] 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()">[&ndash;] 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()">[&ndash;] 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()">[&ndash;] 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()">[&ndash;] 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
+ &#10----&#10Response: <%= @returnCode.to_s %> &#10Request 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' ? "[&ndash;] 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' ? "[&ndash;] 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' ? "[&ndash;] 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' ? "[&ndash;] 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' ? "[&ndash;] 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: []