Examples
Here are a few annotated htty session transcripts to get you started.
Querying a web service
This simple example shows how to explore a read-only web service with htty.
ESV Bible Web Service example #1
$ htty esvapi.org
*** Welcome to htty, the HTTP TTY. Heck To The Yeah!
http://esvapi.org/> get
*** Type fol[low] to follow the 'Location' header received in the response
301 Moved Permanently -- 6 headers -- 373-character body
http://esvapi.org/> follow
http://www.esvapi.org/>
You can point htty at a complete or partial web URL. If you don’t supply a URL, http://0.0.0.0/ (port 80) will be used. You can vary the protocol scheme, userinfo, host, port, path, query string, and fragment as you wish.
The htty shell prompt shows the address of the current request.
The get
command is one of seven HTTP request methods supported. A concise summary of the response is shown when you issue a request.
You can follow redirects using the follow
command. No request is made until you type a request command such as get
or post
.
ESV Bible Web Service example #2
http://www.esvapi.org/> cd /v2/rest/nonexistent/path
http://www.esvapi.org/v2/rest/nonexistent/path> get
404 Not Found -- 5 headers -- 369-character body
http://www.esvapi.org/v2/rest/nonexistent/path> cd ../../passageQuery
http://www.esvapi.org/v2/rest/passageQuery>
You can tweak segments of the address at will. Here we are navigating the site’s path hierarchy, which you can do with relative as well as absolute pathspecs.
ESV Bible Web Service example #3
http://www.esvapi.org/v2/rest/passageQuery> query-set key IP
http://www.esvapi.org/v2/rest/passageQuery?key=IP> query-set passage 'Luke 5:3-6'
http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6> query-set output-format plain-text
http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6&output-format=plain-text> get
200 OK -- 10 headers -- 565-character body
http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6&output-format=plain-text> body
=======================================================
Luke 5:3-6
[3]Getting into one of the boats, which was Simon's, he asked him to
put out a little from the land. And he sat down and taught the people
from the boat. [4]And when he had finished speaking, he said to Simon,
"Put out into the deep and let down your nets for a catch." [5]And Simon
answered, "Master, we toiled all night and took nothing! But at your word
I will let down the nets." [6]And when they had done this, they enclosed
a large number of fish, and their nets were breaking. (ESV)
http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6&output-format=plain-text>
Here we add query-string parameters. Notice that characters that require URL encoding are automatically URL-encoded (unless they are part of a URL-encoded expression).
The headers-response
and body-response
commands reveal the details of a response.
ESV Bible Web Service example #4
http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6&output-format=plain-text> address http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6&output-format=plain-text&include-passage-horizontal-lines=false&include-passage-references=false&include-verse-numbers=false&include-short-copyright=false&line-length=0
http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6&output-format=plain-text&include-passage-horizontal-lines=false&include-passage-references=false&include-verse-numbers=false&include-short-copyright=false&line-length=0> get
200 OK -- 9 headers -- 474-character body
http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6&output-format=plain-text&include-passage-horizontal-lines=false&include-passage-references=false&include-verse-numbers=false&include-short-copyright=false&line-length=0> body
Getting into one of the boats, which was Simon's, he asked him to put out a little from the land. And he sat down and taught the people from the boat. And when he had finished speaking, he said to Simon, "Put out into the deep and let down your nets for a catch." And Simon answered, "Master, we toiled all night and took nothing! But at your word I will let down the nets." And when they had done this, they enclosed a large number of fish, and their nets were breaking.
http://www.esvapi.org/v2/rest/passageQuery?key=IP&passage=Luke%205:3-6&output-format=plain-text&include-passage-horizontal-lines=false&include-passage-references=false&include-verse-numbers=false&include-short-copyright=false&line-length=0> quit
*** Happy Trails To You!
$
There was some cruft in the web service’s response (a horizontal line, a passage reference, verse numbers, a copyright stamp, and line breaks). We eliminate it by using API options provided by the web service we’re talking to.
We do a Julia Child maneuver and use the address
command to change the entire URL, rather than add individual query-string parameters one by one.
Exit your session at any time by typing quit
or hitting Ctrl-D.
Working with cookies
The next example demonstrates htty’s HTTP Secure support and cookies features, as well as how to review and revisit past requests.
Google example #1
https://www.google.com/search?q=Ruby+programming+language> get
*** Type cookies-u[se] to use cookies offered in the response
*** Type fol[low] to follow the 'Location' header received in the response
302 Found -- 8 headers* -- 260-character body
https://www.google.com/search?q=Ruby+programming+language> headers-response
Location: https://encrypted.google.com/search?q=Ruby+programming+language
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Set-Cookie:* O=HAI.; I=CAN; HAS=PRAIVASY?; G00G=RULZ!
Date: Tue, 28 Sep 2010 19:57:23 GMT
Server: gws
Content-Length: 260
X-Xss-Protection: 1; mode=block
https://www.google.com/search?q=Ruby+programming+language> follow
https://encrypted.google.com/search?q=Ruby+programming+language>
The https:// scheme and port 443 imply each other, just as the http:// scheme and port 80 imply each other. If you omit the scheme or the port, it will default to the appropriate value.
Notice that when cookies are offered in a response, a bold asterisk (it looks like a cookie) appears in the response summary. The same cookie symbol appears next to the Set-Cookie header when you display response headers.
Google example #2
https://encrypted.google.com/search?q=Ruby+programming+language> headers-request
User-Agent: htty/1.1.0
https://encrypted.google.com/search?q=Ruby+programming+language> cookies
https://encrypted.google.com/search?q=Ruby+programming+language> cookies-use
*** 4 cookies now in use
https://encrypted.google.com/search?q=Ruby+programming+language> headers-request
User-Agent: htty/1.1.0
Cookie:* O=HAI.; I=CAN; HAS=PRAIVASY?; G00G=RULZ!
https://encrypted.google.com/search?q=Ruby+programming+language> cookies
O: HAI.
I: CAN
HAS: PRAIVASY?
G00G: RULZ!
https://encrypted.google.com/search?q=Ruby+programming+language>
The cookies-use
command copies cookies out of the response into the next request. The cookie symbol appears next to the Cookie header when you display request headers.
Google example #3
https://encrypted.google.com/search?q=Ruby+programming+language> get
200 OK -- 8 headers* -- 41111-character body
https://encrypted.google.com/search?q=Ruby+programming+language> history
1 GET https://www.google.com/search?q=Ruby+programming+language -- 1 header -- empty body
302 Found -- 8 headers* -- 260-character body
2 GET https://www.google.com/search?q=Ruby+programming+language -- 2 headers* -- empty body
200 OK -- 8 headers* -- 41111-character body
https://encrypted.google.com/search?q=Ruby+programming+language> headers-request
User-Agent: htty/1.1.0
Cookie:* O=HAI.; I=CAN; HAS=PRAIVASY?; G00G=RULZ!
https://encrypted.google.com/search?q=Ruby+programming+language> reuse 1
*** Using a copy of request #1
https://encrypted.google.com/search?q=Ruby+programming+language> headers-request
User-Agent: htty/1.1.0
https://encrypted.google.com/search?q=Ruby+programming+language>
An abbreviated history is available through the history
command. Information about requests in the history includes request method, URL, number of headers (and a cookie symbol, if cookies were sent), and the size of the body. Information about responses in the history includes response code, number of headers (and a cookie symbol, if cookies were received), and the size of the body.
Note that history contains only numbered HTTP request and response pairs, not a record of all the commands you enter.
The reuse
command makes a copy of the headers and body of an earlier request for you to build on.
Understanding complex HTTP conversations at a glance using history
Now we’ll look at htty’s HTTP Basic Authentication support and learn how to display unabbreviated transcripts of htty sessions.
Assume that we have the following Sinatra application listening on Sinatra’s default port, 4567.
require 'sinatra'
get '/all-good' do
[200, [['Set-Cookie', 'foo=bar; baz']], 'Hello World!']
end
put '/huh' do
[404, 'What?']
end
delete '/hurl' do
[500, 'Barf!']
end
post '/submit-novel' do
redirect '/all-good'
end
This application expects GET and POST requests and responds in various contrived ways.
Sinatra application example #1
http://0.0.0.0:4567/all-good> get
*** Type cookies-u[se] to use cookies offered in the response
200 OK -- 6 headers* -- 12-character body
http://0.0.0.0:4567/all-good> cookies-use
*** 2 cookies now in use
http://0.0.0.0:4567/all-good> cd /huh
http://0.0.0.0:4567/huh> put
404 Not Found -- 5 headers -- 5-character body
http://0.0.0.0:4567/huh> userinfo-set [email protected] secret
http://htty%40nilsjonsson.com:[email protected]:4567/huh> cd /hurl
http://htty%40nilsjonsson.com:[email protected]:4567/hurl> delete
500 Internal Server Error -- 5 headers -- 5-character body
http://htty%40nilsjonsson.com:[email protected]:4567/hurl> cookies-remove-all
http://htty%40nilsjonsson.com:[email protected]:4567/hurl> userinfo-unset
http://0.0.0.0:4567/hurl> body-set
*** Enter two blank lines, or hit Ctrl-D, to signify the end of the body
If a body
meet a body
comin' through the rye
http://0.0.0.0:4567/hurl> header-set Author 'J. D. Salinger'
http://0.0.0.0:4567/hurl> cd /submit-novel
http://0.0.0.0:4567/submit-novel> post
*** Type fol[low] to follow the 'Location' header received in the response
302 Found -- 6 headers -- empty body
http://0.0.0.0:4567/submit-novel>
When you change the userinfo portion of the address, or the entire address, the appropriate HTTP Basic Authentication header is created for you automatically. Notice that characters that require URL encoding are automatically URL-encoded (unless they are part of a URL-encoded expression).
When userinfo is supplied in a request, a bold mercantile symbol ( @ ) appears next to the resulting Authorization header when you display request headers (see below).
Type body-set
to enter body data, and terminate it by entering two consecutive blank lines, or by hitting Ctrl-D. The body will only be sent for POST and PUT requests. The appropriate Content-Length header is created for you automatically (see below).
Different response codes are rendered with colors that suggest their meaning:
- Response codes between 200 and 299 appear black on green to indicate success
- Response codes between 300 and 399 appear white on blue to indicate redirection
- Response codes between 400 and 499 appear white on red to indicate failure
- Response codes between 500 and 599 appear flashing black on yellow to indicate a server error
Sinatra application example #2
http://0.0.0.0:4567/submit-novel> history-verbose
1 GET http://0.0.0.0:4567/all-good -- 1 header -- empty body
User-Agent: htty/1.1.0
200 OK -- 6 headers* -- 12-character body
Content-Type: text/html
Content-Length: 12
Server: WEBrick/1.3.1 (Ruby/1.9.3/2010-09-25)
Date: Tue, 28 Sep 2010 21:10:58 GMT
Connection: Keep-Alive
Set-Cookie:* foo=bar; baz
Hello World!
------------------------------------------------------------------------------
2 PUT http://0.0.0.0:4567/huh -- 3 headers* -- empty body
User-Agent: htty/1.1.0
Content-Length: 0
Cookie:* foo=bar; baz
404 Not Found -- 5 headers -- 5-character body
Content-Type: text/html
Content-Length: 5
Server: WEBrick/1.3.1 (Ruby/1.9.3/2010-09-25)
Date: Tue, 28 Sep 2010 21:11:05 GMT
Connection: Keep-Alive
What?
------------------------------------------------------------------------------
3 DELETE http://htty%40nilsjonsson.com:[email protected]:4567/hurl -- 3 headers* -- empty body
User-Agent: htty/1.1.0
Cookie:* foo=bar; baz
Authorization:@ Basic aHR0eUBuaWxzam9uc3NvbjpzZWNyZXQ=
500 Internal Server Error -- 5 headers -- 5-character body
Content-Type: text/html
Content-Length: 5
Server: WEBrick/1.3.1 (Ruby/1.9.3/2010-09-25)
Date: Tue, 28 Sep 2010 21:12:17 GMT
Connection: Keep-Alive
Barf!
------------------------------------------------------------------------------
4 POST http://0.0.0.0:4567/submit-novel -- 3 headers -- 46-character body
User-Agent: htty/1.1.0
Content-Length: 46
Author: J. D. Salinger
If a body
meet a body
comin' through the rye
302 Found -- 6 headers -- empty body
Content-Type: text/html
Location: http://0.0.0.0:4567/all-good
Content-Length: 0
Server: WEBrick/1.3.1 (Ruby/1.9.3/2010-09-25)
Date: Tue, 28 Sep 2010 21:13:44 GMT
Connection: Keep-Alive
http://0.0.0.0:4567/submit-novel>
As with the abbreviated history demonstrated earlier, verbose history shows a numbered list of requests and the responses they elicited. All information exchanged between client and server is shown.
Getting help
You can learn how to use htty commands from within htty.
htty’s built-in help
http://0.0.0.0/> help
Navigation
a[ddress] ADDRESS Changes the address of the
request
cd PATH Alias for path[-set]
fol[low] Changes the address of the
request to the value of the
response's 'Location' header
fragment-c[lear] Alias for
fragment-u[nset]
fragment-s[et] FRAGMENT Sets the fragment of the
request's address
fragment-u[nset] Removes the fragment from the
request's address
history Displays previous
request-response activity in
this session
history-[verbose] Displays the details of previous
request-response activity in
this session
ho[st-set] HOST Changes the host of the
request's address
path[-set] PATH Changes the path of the
request's address
por[t-set] PORT Changes the TCP port of the
request's address
query-a[dd] NAME [VALUE [NAME [VALUE ...]]] Adds query-string parameters to
the request's address
query-c[lear] Alias for
query-unset-[all]
query-r[emove] NAME [VALUE] Removes query-string parameters
from the end of the request's
address
query-s[et] NAME [VALUE [NAME [VALUE ...]]] Sets query-string parameters in
the request's address
query-unset NAME [VALUE] Removes query-string parameters
from the request's address
query-unset-[all] Clears the query string of the
request's address
r[euse] INDEX Copies a previous request by the
index number shown in history
sc[heme-set] SCHEME Changes the scheme (protocol
identifier) of the request's
address
userinfo-c[lear] Alias for
userinfo-u[nset]
userinfo-s[et] USERNAME [PASSWORD] Sets the userinfo of the
request's address
userinfo-u[nset] Removes the userinfo from the
request's address
Building Requests
body-c[lear] Alias for body-u[nset]
body-request Displays the body of the request
body-s[et] Sets the body of the request
body-u[nset] Clears the body of the request
cookie-a[dd] NAME [VALUE] Alias for cookies-a[dd]
cookie-r[emove] NAME Alias for cookies-remove
cookies Displays the cookies of the
request
cookies-a[dd] NAME [VALUE] Adds a cookie to the request
cookies-c[lear] Alias for
cookies-remove-[all]
cookies-remove NAME Removes from the request the
last cookie having a particular
name
cookies-remove-[all] Removes all cookies from the
request
cookies-u[se] Uses cookies offered in the
response
form (Help for form is not
available)
form-a[dd] (Help for form-a[dd] is
not available)
form-c[lear] Alias for
form-remove-[all]
form-remove (Help for form-remove is
not available)
form-remove-[all] (Help for
form-remove-[all] is not
available)
header-s[et] NAME VALUE Alias for headers-s[et]
header-u[nset] NAME Alias for headers-unset
headers-c[lear] Alias for
headers-unset-[all]
headers-req[uest] Displays the headers of the
request
headers-s[et] NAME VALUE Sets a header of the request
headers-unset NAME Removes a header of the request
headers-unset-[all] Removes all headers from the
request
Issuing Requests
d[elete] Alias for http-d[elete]
g[et] Alias for http-g[et]
http-d[elete] Issues an HTTP DELETE using the
current request
http-g[et] Issues an HTTP GET using the
current request
http-h[ead] Issues an HTTP HEAD using the
current request
http-o[ptions] Issues an HTTP OPTIONS using the
current request
http-po[st] Issues an HTTP POST using the
current request
http-pu[t] Issues an HTTP PUT using the
current request
http-t[race] Issues an HTTP TRACE using the
current request
pos[t] Alias for http-po[st]
pu[t] Alias for http-pu[t]
Inspecting Responses
body[-response] Displays the body of the
response
headers[-response] Displays the headers of the
response
st[atus] Displays the status of the
response
Preferences
ssl-verification Displays the preference for SSL
certificate verification
ssl-verification-of[f] Disables SSL certificate
verification
ssl-verification-on Reenables SSL certificate
verification
Miscellaneous
e[xit] Alias for qui[t]
hel[p] [COMMAND] Displays this help table, or
help on the specified command
qui[t] Quits htty
un[do] (Help for un[do] is not
available)
http://0.0.0.0/>
The help
command takes an optional argument of the abbreviated or full name of a command.