Request and response messages are similar. Both messages consist of:
Request
Request-Line
example request line:
Reponse
Status-Line
example status line:
curl -v golang.org
Development of HTTP was initiated by Tim Berners-Lee at CERN in 1989. Standards development of HTTP was coordinated by the Internet Engineering Task Force (IETF) and the World Wide Web Consortium (W3C), culminating in the publication of a series of Requests for Comments (RFCs).
The first definition of HTTP/1.1, the version of HTTP in common use, occurred in RFC 2068 in 1997, although this was obsoleted by RFC 2616 in 1999. In 2014, RFC2616 was replaced by multiple RFCs (7230-7237)
A later version, the successor HTTP/2, was standardized in 2015, and is now supported by major web servers.
A Request for Comments (RFC) is a type of publication from the Internet Engineering Task Force (IETF) and the Internet Society (ISOC), the principal technical development and standards-setting bodies for the Internet.
An RFC is authored by engineers and computer scientists in the form of a memorandum describing methods, behaviors, research, or innovations applicable to the working of the Internet and Internet-connected systems. It is submitted either for peer review or simply to convey new concepts, information, or (occasionally) engineering humor. The IETF adopts some of the proposals published as RFCs as Internet Standards.
Request for Comments documents were invented by Steve Crocker in 1969 to help record unofficial notes on the development of ARPANET. RFCs have since become official documents of Internet specifications, communications protocols, procedures, and events.
The Internet Engineering Task Force (IETF) develops and promotes voluntary Internet standards, in particular the standards that comprise the Internet protocol suite (TCP/IP). It is an open standards organization, with no formal membership or membership requirements. All participants and managers are volunteers, though their work is usually funded by their employers or sponsors.
The IETF started out as an activity supported by the U.S. federal government, but since 1993 it has operated as a standards development function under the auspices of the Internet Society, an international membership-based non-profit organization.
HTTP was created for the World Wide Web (WWW) architecture and has evolved over time to support the scalability needs of a worldwide hypertext system. Much of that architecture is reflected in the terminology and syntax productions used to define HTTP.
HTTP is a stateless request/response protocol that operates by exchanging messages across a reliable TRANSPORT- or SESSION-layer “CONNECTION”.
An HTTP “CLIENT” is a program that establishes a CONNECTION to a server for the purpose of sending one or more HTTP requests.
An HTTP “SERVER” is a program that accepts CONNECTIONS in order to service HTTP requests by sending HTTP responses.
The terms “client” and “server” refer only to the roles that these programs perform for a particular connection. The same program might act as a client on some connections and a server on others. The term “user agent” refers to any of the various client programs that initiate a request, including (but not limited to) browsers, spiders (web-based robots), command-line tools, custom applications, and mobile apps. The term “origin server” refers to the program that can originate authoritative responses for a given target resource. The terms “sender” and “recipient” refer to any implementation that sends or receives a given message, respectively.
HTTP relies upon the Uniform Resource Identifier (URI) standard to indicate the target resource and relationships between resources. Messages are passed in a format similar to that used by Internet mail and the Multipurpose Internet Mail Extensions (MIME) (see Appendix A of [RFC7231] for the differences between HTTP and MIME messages).
Most HTTP communication consists of a retrieval request (GET) for a representation of some resource identified by a URI. In the simplest case, this might be accomplished via a single bidirectional CONNECTION (===) between the user agent (UA) and the origin server (O).
request > UA ======================================= O
< response
A client sends an HTTP REQUEST to a server in the form of a REQUEST MESSAGE, beginning with a REQUEST-LINE that includes a method, URI, and protocol version, followed by header fields containing request modifiers, client information, and representation metadata, an empty line to indicate the end of the header section, and finally a message body containing the payload body (if any, Section 3.3).
A server responds to a client’s request by sending one or more HTTP RESPONSE MESSAGES, each beginning with a STATUS LINE that includes the protocol version, a success or error code, and textual reason phrase, possibly followed by header fields containing server information, resource metadata, and representation metadata, an empty line to indicate the end of the header section, and finally a message body containing the payload body (if any, Section 3.3).
A connection might be used for multiple REQUEST/RESPONSE exchanges, as defined in Section 6.3.
The following example illustrates a typical message exchange for a GET request on the URI “http://www.example.com/hello.txt”:
GET /hello.txt HTTP/1.1
User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
Host: www.example.com
Accept-Language: en, mi
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: “34aa387-d-1568eb00”
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain
Hello World! My payload includes a trailing CRLF.
When considering the design of HTTP, it is easy to fall into a trap of thinking that all user agents are general-purpose browsers and all origin servers are large public websites. That is not the case in practice. Common HTTP USER AGENTS include household appliances, stereos, scales, firmware update scripts, command-line programs, mobile apps, and communication devices in a multitude of shapes and sizes. Likewise, common HTTP ORIGIN SERVERS include home automation units, configurable networking components, office machines, autonomous robots, news feeds, traffic cameras, ad selectors, and video-delivery platforms.
The term “USER AGENT” does not imply that there is a human user directly interacting with the software agent at the time of a request. In many cases, a user agent is installed or configured to run in the background and save its results for later inspection (or save only a subset of those results that might be interesting or erroneous). Spiders, for example, are typically given a start URI and configured to follow certain behavior while crawling the Web as a hypertext graph.
package main
import (
"fmt"
"io"
"log"
"net"
)
func main() {
li, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln(err)
}
defer li.Close()
for {
conn, err := li.Accept()
if err != nil {
log.Println(err)
continue
}
io.WriteString(conn, "\nHello from TCP server\n")
fmt.Fprintln(conn, "How is your day?")
fmt.Fprintf(conn, "%v", "Well, I hope!")
conn.Close()
}
}
package main
import (
"bufio"
"fmt"
"log"
"net"
)
func main() {
li, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln(err)
}
defer li.Close()
for {
conn, err := li.Accept()
if err != nil {
log.Println(err)
continue
}
go handle(conn)
}
}
func handle(conn net.Conn) {
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
ln := scanner.Text()
fmt.Println(ln)
}
defer conn.Close()
// we never get here
// we have an open stream connection
// how does the above reader know when it's done?
fmt.Println("Code got here.")
}
package main
import (
"bufio"
"fmt"
"log"
"net"
)
func main() {
li, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln(err)
}
defer li.Close()
for {
conn, err := li.Accept()
if err != nil {
log.Println(err)
continue
}
go handle(conn)
}
}
func handle(conn net.Conn) {
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
ln := scanner.Text()
fmt.Println(ln)
fmt.Fprintf(conn, "I heard you say: %s\n", ln)
}
defer conn.Close()
// we never get here
// we have an open stream connection
// how does the above reader know when it's done?
fmt.Println("Code got here.")
}
package main
import (
"bufio"
"fmt"
"log"
"net"
"time"
)
func main() {
li, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln(err)
}
defer li.Close()
for {
conn, err := li.Accept()
if err != nil {
log.Println(err)
continue
}
go handle(conn)
}
}
func handle(conn net.Conn) {
err := conn.SetDeadline(time.Now().Add(10 * time.Second))
if err != nil {
log.Fatalln("CONN TIMEOUT")
}
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
ln := scanner.Text()
fmt.Println(ln)
fmt.Fprintf(conn, "I heard you say: %s\n", ln)
}
defer conn.Close()
// now we get here
// the connection will time out
// that breaks us out of the scanner loop
fmt.Println("***CODE GOT HERE***")
}
import ( “fmt” “io/ioutil” “log” “net” )
func main() { conn, err := net.Dial(“tcp”, “localhost:8080”) if err != nil { log.Fatalln(err) } defer conn.Close()
bs, err := ioutil.ReadAll(conn)
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(bs)) } ```
import ( “fmt” “log” “net” )
func main() { conn, err := net.Dial(“tcp”, “localhost:8080”) if err != nil { log.Fatalln(err) } defer conn.Close()
fmt.Fprintln(conn, "I dialed you.") } ```
import ( “bufio” “fmt” “log” “net” “strings” )
func main() { li, err := net.Listen(“tcp”, “:8080”) if err != nil { log.Fatalln(err) } defer li.Close()
for {
conn, err := li.Accept()
if err != nil {
log.Println(err)
continue
}
go handle(conn)
} }
func handle(conn net.Conn) { scanner := bufio.NewScanner(conn) for scanner.Scan() { ln := strings.ToLower(scanner.Text()) bs := []byte(ln) r := rot13(bs)
fmt.Fprintf(conn, "%s - %s\n\n", ln, r)
} }
func rot13(bs []byte) []byte { var r13 = make([]byte, len(bs)) for i, v := range bs { // ascii 97 - 122 if v <= 109 { r13[i] = v + 13 } else { r13[i] = v - 13 } } return r13 }
- memory database
```go
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
"strings"
)
func main() {
li, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln(err)
}
defer li.Close()
for {
conn, err := li.Accept()
if err != nil {
log.Println(err)
continue
}
go handle(conn)
}
}
func handle(conn net.Conn) {
defer conn.Close()
// instructions
io.WriteString(conn, "\r\nIN-MEMORY DATABASE\r\n\r\n"+
"USE:\r\n"+
"\tSET key value \r\n"+
"\tGET key \r\n"+
"\tDEL key \r\n\r\n"+
"EXAMPLE:\r\n"+
"\tSET fav chocolate \r\n"+
"\tGET fav \r\n\r\n\r\n")
// read & write
data := make(map[string]string)
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
ln := scanner.Text()
fs := strings.Fields(ln)
// logic
if len(fs) < 1 {
continue
}
switch fs[0] {
case "GET":
k := fs[1]
v := data[k]
fmt.Fprintf(conn, "%s\r\n", v)
case "SET":
if len(fs) != 3 {
fmt.Fprintln(conn, "EXPECTED VALUE\r\n")
continue
}
k := fs[1]
v := fs[2]
data[k] = v
case "DEL":
k := fs[1]
delete(data, k)
default:
fmt.Fprintln(conn, "INVALID COMMAND "+fs[0]+"\r\n")
continue
}
}
}