emacs.d/clones/ruslanspivak.com/lsbaws-part1/index.html

445 lines
29 KiB
HTML
Raw Normal View History

2022-10-07 19:32:11 +02:00
<!DOCTYPE html>
<html lang="en"
xmlns:og="http://ogp.me/ns#"
xmlns:fb="https://www.facebook.com/2008/fbml">
<head>
<title>Lets Build A Web Server. Part 1. - Ruslan's Blog</title>
<!-- Using the latest rendering mode for IE -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="canonical" href="index.html">
<meta name="author" content="Ruslan Spivak" />
<meta name="description" content="Out for a walk one day, a woman came across a construction site and saw three men working. She asked the first man, “What are you doing?” Annoyed by the question, the first man barked, “Cant you see that Im laying bricks?” Not satisfied with the answer, she …" />
<meta property="og:site_name" content="Ruslan's Blog" />
<meta property="og:type" content="article"/>
<meta property="og:title" content="Lets Build A Web Server. Part 1."/>
<meta property="og:url" content="https://ruslanspivak.com/lsbaws-part1/"/>
<meta property="og:description" content="Out for a walk one day, a woman came across a construction site and saw three men working. She asked the first man, “What are you doing?” Annoyed by the question, the first man barked, “Cant you see that Im laying bricks?” Not satisfied with the answer, she …"/>
<meta property="article:published_time" content="2015-03-09" />
<meta property="article:section" content="blog" />
<meta property="article:author" content="Ruslan Spivak" />
<meta name="twitter:card" content="summary">
<meta name="twitter:domain" content="https://ruslanspivak.com">
<!-- Bootstrap -->
<link rel="stylesheet" href="../theme/css/bootstrap.min.css" type="text/css"/>
<link href="../theme/css/font-awesome.min.css" rel="stylesheet">
<link href="../theme/css/pygments/tango.css" rel="stylesheet">
<link href="../theme/css/typogrify.css" rel="stylesheet">
<link rel="stylesheet" href="../theme/css/style.css" type="text/css"/>
<link href="../static/custom.css" rel="stylesheet">
<link href="../feeds/all.atom.xml" type="application/atom+xml" rel="alternate"
title="Ruslan's Blog ATOM Feed"/>
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="../index.html" class="navbar-brand">
Ruslan's Blog </a>
</div>
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav">
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="../pages/about.html"><i class="fa fa-question"></i><span class="icon-label">About</span></a></li>
<li><a href="../archives.html"><i class="fa fa-th-list"></i><span class="icon-label">Archives</span></a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
</div> <!-- /.navbar -->
<!-- Banner -->
<!-- End Banner -->
<div class="container">
<div class="row">
<div class="col-sm-9">
<section id="content">
<article>
<header class="page-header">
<h1>
<a href="index.html"
rel="bookmark"
title="Permalink to Lets Build A Web Server. Part 1.">
Let&#8217;s Build A Web Server. Part&nbsp;1.
</a>
</h1>
</header>
<div class="entry-content">
<div class="panel">
<div class="panel-body">
<footer class="post-info">
<span class="label label-default">Date</span>
<span class="published">
<i class="fa fa-calendar"></i><time datetime="2015-03-09T08:00:00-04:00"> Mon, March 09, 2015</time>
</span>
</footer><!-- /.post-info --> </div>
</div>
<p>Out for a walk one day, a woman came across a construction site and saw three men working.
She asked the first man, “What are you doing?”
Annoyed by the question, the first man barked, “Cant you see that Im laying bricks?” Not satisfied with the answer, she asked the second man what he was doing.
The second man answered, “Im building a brick wall.” Then, turning his attention to the first man, he said, “Hey, you just passed the end of the wall. You need to take off that last brick.” Again not satisfied with the answer, she asked the third man what he was doing. And the man said to her while looking up in the sky, “I am building the biggest cathedral this world has ever known.” While he was standing there and looking up in the sky the other two men started arguing about the errant brick. The man turned to the first two men and said, “Hey guys, dont worry about that brick. Its an inside wall, it will get plastered over and no one will ever see that brick. Just move on to another&nbsp;layer.”</p>
<p>The moral of the story is that when you know the whole system and understand how different pieces fit together (bricks, walls, cathedral), you can identify and fix problems faster (errant&nbsp;brick).</p>
<p>What does it have to do with creating your own Web server from&nbsp;scratch?</p>
<p><strong>I believe to become a better developer you <span class="caps">MUST</span> get a better understanding of the underlying software systems you use on a daily basis and that includes programming languages, compilers and interpreters, databases and operating systems, web servers and web frameworks. And, to get a better and deeper understanding of those systems you <span class="caps">MUST</span> re-build them from scratch, brick by brick, wall by&nbsp;wall.</strong></p>
<p>Confucius put it this&nbsp;way:</p>
<blockquote>
<p><em><span class="dquo">&#8220;</span>I hear and I&nbsp;forget.&#8221;</em></p>
</blockquote>
<p><img alt="Hear" src="../lsbasi-part4/LSBAWS_confucius_hear.png" width="640"></p>
<blockquote>
<p><em><span class="dquo">&#8220;</span>I see and I&nbsp;remember.&#8221;</em></p>
</blockquote>
<p><img alt="See" src="../lsbasi-part4/LSBAWS_confucius_see.png" width="640"></p>
<blockquote>
<p><em><span class="dquo">&#8220;</span>I do and I&nbsp;understand.&#8221;</em></p>
</blockquote>
<p><img alt="Do" src="../lsbasi-part4/LSBAWS_confucius_do.png" width="640"></p>
<p>I hope at this point youre convinced that its a good idea to start re-building different software systems to learn how they&nbsp;work.</p>
<p>In this three-part series I will show you how to build your own basic Web server. Lets get&nbsp;started.</p>
<p>First things first, what is a Web&nbsp;server?</p>
<p><img alt="HTTP Request/Response" src="LSBAWS_HTTP_request_response.png"></p>
<p>In a nutshell its a networking server that sits on a physical server (oops, a server on a server) and waits for a client to send a request. When it receives a request, it generates a response and sends it back to the client. The communication between a client and a server happens using <span class="caps">HTTP</span> protocol. A client can be your browser or any other software that speaks <span class="caps">HTTP</span>.</p>
<p>What would a very simple implementation of a Web server look like?
Here is my take on it. The example is in Python (tested on Python3.7+) but even if you dont know Python (its a very easy language to pick up, try it!) you still should be able to understand concepts from the code and explanations&nbsp;below:</p>
<div class="highlight"><pre><span></span><span class="c1"># Python3.7+</span>
<span class="kn">import</span> <span class="nn">socket</span>
<span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="mi">8888</span>
<span class="n">listen_socket</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="n">listen_socket</span><span class="o">.</span><span class="n">setsockopt</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">SOL_SOCKET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SO_REUSEADDR</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">listen_socket</span><span class="o">.</span><span class="n">bind</span><span class="p">((</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">))</span>
<span class="n">listen_socket</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s1">&#39;Serving HTTP on port {PORT} ...&#39;</span><span class="p">)</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">client_connection</span><span class="p">,</span> <span class="n">client_address</span> <span class="o">=</span> <span class="n">listen_socket</span><span class="o">.</span><span class="n">accept</span><span class="p">()</span>
<span class="n">request_data</span> <span class="o">=</span> <span class="n">client_connection</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">request_data</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">))</span>
<span class="n">http_response</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&quot;&quot;&quot;</span><span class="se">\</span>
<span class="s2">HTTP/1.1 200 OK</span>
<span class="s2">Hello, World!</span>
<span class="s2">&quot;&quot;&quot;</span>
<span class="n">client_connection</span><span class="o">.</span><span class="n">sendall</span><span class="p">(</span><span class="n">http_response</span><span class="p">)</span>
<span class="n">client_connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
<p>Save the above code as <em>webserver1.py</em> or download it directly from <a href="https://github.com/rspivak/lsbaws/blob/master/part1/webserver1.py" title="GitHub">GitHub</a> and run it on the command line like&nbsp;this</p>
<div class="highlight"><pre><span></span>$ python webserver1.py
Serving HTTP on port <span class="m">8888</span>
</pre></div>
<p>Now type in the following <span class="caps">URL</span> in your Web browsers address bar <a href="http://localhost:8888/hello" title="Hello">http://localhost:8888/hello</a>, hit Enter, and see magic in action. You should see <em>&#8220;Hello, World!&#8221;</em> displayed in your browser like&nbsp;this:</p>
<p><img alt="Browser &quot;Hello, World!&quot;" src="browser_hello_world.png"></p>
<p>Just do it, seriously. I will wait for you while youre testing&nbsp;it.</p>
<p>Done? Great. Now lets discuss how it all actually&nbsp;works.</p>
<p>First lets start with the Web address youve entered. Its called an <a href="http://en.wikipedia.org/wiki/Uniform_resource_locator"><span class="caps">URL</span></a> and here is its basic&nbsp;structure:</p>
<p><img alt="URL Structure" src="LSBAWS_URL_Web_address.png" width="480"></p>
<p>This is how you tell your browser the address of the Web server it needs to find and connect to and the page (path) on the server to fetch for you.
Before your browser can send a <span class="caps">HTTP</span> request though, it first needs to establish a <span class="caps">TCP</span> connection with the Web server. Then it sends an <span class="caps">HTTP</span> request over the <span class="caps">TCP</span> connection to the server and waits for the server to send an <span class="caps">HTTP</span> response back. And when your browser receives the response it displays it, in this case it displays “Hello,&nbsp;World!”</p>
<p>Lets explore in more detail how the client and the server establish a <span class="caps">TCP</span> connection before sending <span class="caps">HTTP</span> requests and responses. To do that they both use so-called <em>sockets</em>. Instead of using a browser directly you are going to simulate your browser manually by using <em>telnet</em> on the command&nbsp;line.</p>
<p>On the same computer youre running the Web server fire up a telnet session on the command line specifying a host to connect to <em>localhost</em> and the port to connect to <em>8888</em> and then press&nbsp;Enter:</p>
<div class="highlight"><pre><span></span>$ telnet localhost <span class="m">8888</span>
Trying <span class="m">127</span>.0.0.1 …
Connected to localhost.
</pre></div>
<p>At this point youve established a <span class="caps">TCP</span> connection with the server running on your local host and ready to send and receive <span class="caps">HTTP</span> messages. In the picture below you can see a standard procedure a server has to go through to be able to accept new <span class="caps">TCP</span> connections.
<img alt="Socket accept" src="LSBAWS_socket.png" width="780"></p>
<p>In the same telnet session type <strong><em><span class="caps">GET</span> /hello <span class="caps">HTTP</span>/1.1</em></strong> and hit&nbsp;Enter:</p>
<div class="highlight"><pre><span></span>$ telnet localhost <span class="m">8888</span>
Trying <span class="m">127</span>.0.0.1 …
Connected to localhost.
GET /hello HTTP/1.1
HTTP/1.1 <span class="m">200</span> OK
Hello, World!
</pre></div>
<p>Youve just manually simulated your browser! You sent an <span class="caps">HTTP</span> request and got an <span class="caps">HTTP</span> response back. This is the basic structure of an <span class="caps">HTTP</span>&nbsp;request:</p>
<p><img alt="HTTP Request Aanatomy" src="LSBAWS_HTTP_request_anatomy.png" width="560"></p>
<p>The <span class="caps">HTTP</span> request consists of the line indicating the <span class="caps">HTTP</span> method (<strong><em><span class="caps">GET</span></em></strong>, because we are asking our server to return us something), the path <em>/hello</em> that indicates a <em>“page”</em> on the server we want and the protocol&nbsp;version.</p>
<p>For simplicitys sake our Web server at this point completely ignores the above request line. You could just as well type in any garbage instead of <em>&#8220;<span class="caps">GET</span> /hello <span class="caps">HTTP</span>/1.1&#8221;</em> and you would still get back a <em>&#8220;Hello, World!&#8221;</em>&nbsp;response.</p>
<p>Once youve typed the request line and hit Enter the client sends the request to the server, the server reads the request line, prints it and returns the proper <span class="caps">HTTP</span>&nbsp;response.</p>
<p>Here is the <span class="caps">HTTP</span> response that the server sends back to your client (<em>telnet</em> in this case):
<img alt="HTTP Response Anatomy" src="LSBAWS_HTTP_response_anatomy.png" width="560"></p>
<p>Lets dissect it. The response consists of a status line <em><span class="caps">HTTP</span>/1.1 200 <span class="caps">OK</span></em>, followed by a required empty line, and then the <span class="caps">HTTP</span> response&nbsp;body.</p>
<p>The response status line <em><span class="caps">HTTP</span>/1.1 200 <span class="caps">OK</span></em> consists of the <em><span class="caps">HTTP</span> Version</em>, the <em><span class="caps">HTTP</span> status code</em> and the <em><span class="caps">HTTP</span> status code reason</em> phrase <em><span class="caps">OK</span></em>. When the browser gets the response, it displays the body of the response and thats why you see <em>&#8220;Hello, World!&#8221;</em> in your&nbsp;browser.</p>
<p>And thats the basic model of how a Web server works. To sum it up: The Web server creates a listening socket and starts accepting new connections in a loop. The client initiates a <span class="caps">TCP</span> connection and, after successfully establishing it, the client sends an <span class="caps">HTTP</span> request to the server and the server responds with an <span class="caps">HTTP</span> response that gets displayed to the user. To establish a <span class="caps">TCP</span> connection both clients and servers use <em>sockets</em>.</p>
<p>Now you have a very basic working Web server that you can test with your browser or some other <span class="caps">HTTP</span> client. As youve seen and hopefully tried, you can also be a human <span class="caps">HTTP</span> client too, by using <em>telnet</em> and typing <span class="caps">HTTP</span> requests&nbsp;manually.</p>
<p>Heres a question for you: “How do you run a Django application, Flask application, and Pyramid application under your freshly minted Web server without making a single change to the server to accommodate all those different Web&nbsp;frameworks?”</p>
<p>I will show you exactly how in <a href="../lsbaws-part2/index.html">Part 2</a> of the series. Stay&nbsp;tuned.</p>
<p><br/>
<em>Resources used in preparation for this article (links are affiliate&nbsp;links):</em></p>
<ol>
<li>
<p><a href="http://www.amazon.com/gp/product/0131411551/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0131411551&linkCode=as2&tag=russblo0b-20&linkId=2F4NYRBND566JJQL">Unix Network Programming, Volume 1: The Sockets Networking <span class="caps">API</span> (3rd Edition)</a><img src="http://ir-na.amazon-adsystem.com/e/ir?t=russblo0b-20&l=as2&o=1&a=0131411551" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
</li>
<li>
<p><a href="http://www.amazon.com/gp/product/0321637739/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321637739&linkCode=as2&tag=russblo0b-20&linkId=3ZYAKB537G6TM22J">Advanced Programming in the <span class="caps">UNIX</span> Environment, 3rd Edition</a><img src="http://ir-na.amazon-adsystem.com/e/ir?t=russblo0b-20&l=as2&o=1&a=0321637739" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
</li>
<li>
<p><a href="http://www.amazon.com/gp/product/1593272200/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1593272200&linkCode=as2&tag=russblo0b-20&linkId=CHFOMNYXN35I2MON">The Linux Programming Interface: A Linux and <span class="caps">UNIX</span> System Programming Handbook</a><img src="http://ir-na.amazon-adsystem.com/e/ir?t=russblo0b-20&l=as2&o=1&a=1593272200" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
</li>
<li>
<p><a href="http://www.amazon.com/gp/product/0814420303/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0814420303&linkCode=as2&tag=russblo0b-20&linkId=HY2LNXTSGPPFZ2EV">Lead with a Story</a><img src="http://ir-na.amazon-adsystem.com/e/ir?t=russblo0b-20&l=as2&o=1&a=0814420303" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
</li>
</ol>
<p><br/></p>
<blockquote>
<p><em><strong><span class="caps">UPDATE</span>: Sat, July 13,&nbsp;2019</strong></em></p>
<ul>
<li>
<p>Updated the server code to run under Python&nbsp;3.7+</p>
</li>
<li>
<p>Added resources used in preparation for the&nbsp;article</p>
</li>
</ul>
</blockquote>
<p><br/>
<p>If you want to get my newest articles in your inbox, then enter your email address below and click "Get Updates!"</p>
<!-- Begin MailChimp Signup Form -->
<link href="https://cdn-images.mailchimp.com/embedcode/classic-081711.css"
rel="stylesheet" type="text/css">
<style type="text/css">
#mc_embed_signup {
background: #f5f5f5;
clear: left;
font: 18px Helvetica,Arial,sans-serif;
}
#mc_embed_signup form {
text-align: center;
padding: 20px 0 10px 3%;
}
#mc_embed_signup .mc-field-group input {
display: inline;
width: 40%;
}
#mc_embed_signup div.response {
width: 100%;
}
</style>
<div id="mc_embed_signup">
<form
action="https://ruslanspivak.us4.list-manage.com/subscribe/post?u=7dde30eedc045f4670430c25f&amp;id=6f69f44e03"
method="post"
id="mc-embedded-subscribe-form"
name="mc-embedded-subscribe-form"
class="validate"
target="_blank" novalidate>
<div id="mc_embed_signup_scroll">
<div class="mc-field-group">
<label for="mce-NAME">Enter Your First Name *</label>
<input type="text" value="" name="NAME" class="required" id="mce-NAME">
</div>
<div class="mc-field-group">
<label for="mce-EMAIL">Enter Your Best Email *</label>
<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
</div>
<div id="mce-responses" class="clear">
<div class="response" id="mce-error-response" style="display:none"></div>
<div class="response" id="mce-success-response" style="display:none"></div>
</div>
<!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
<div style="position: absolute; left: -5000px;"><input type="text" name="b_7dde30eedc045f4670430c25f_6f69f44e03" tabindex="-1" value=""></div>
<div class="clear"><input type="submit" value="Get Updates!" name="subscribe" id="mc-embedded-subscribe" class="button" style="background-color: rgb(63, 146, 236);"></div>
</div>
</form>
</div>
<!-- <script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[1]='NAME';ftypes[1]='text';fnames[0]='EMAIL';ftypes[0]='email';}(jQuery));var $mcj = jQuery.noConflict(true);</script> -->
<!--End mc_embed_signup-->
</p>
<p><br/>
<strong>All articles in this&nbsp;series:</strong></p>
<ul>
<li><a href="index.html">Let&#8217;s Build A Web Server. Part&nbsp;1.</a></li>
<li><a href="../lsbaws-part2/index.html">Let&#8217;s Build A Web Server. Part&nbsp;2.</a></li>
<li><a href="../lsbaws-part3/index.html">Let&#8217;s Build A Web Server. Part&nbsp;3.</a></li>
</ul>
</div>
<!-- /.entry-content -->
<hr/>
<section class="comments" id="comments">
<h2>Comments</h2>
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'ruslanspivak'; // required: replace example with your forum shortname
var disqus_identifier = 'lets-build-a-web-server-part-1';
var disqus_url = 'https://ruslanspivak.com/lsbaws-part1/';
var disqus_config = function () {
this.language = "en";
};
/* * * DON'T EDIT BELOW THIS LINE * * */
(function () {
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by
Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
</section>
</article>
</section>
</div>
<div class="col-sm-3" id="sidebar">
<aside>
<section class="well well-sm">
<ul class="list-group list-group-flush">
<li class="list-group-item"><h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Social</span></h4>
<ul class="list-group" id="social">
<li class="list-group-item"><a href="https://github.com/rspivak/"><i class="fa fa-github-square fa-lg"></i> github</a></li>
<li class="list-group-item"><a href="https://twitter.com/rspivak"><i class="fa fa-twitter-square fa-lg"></i> twitter</a></li>
<li class="list-group-item"><a href="https://linkedin.com/in/ruslanspivak/"><i class="fa fa-linkedin-square fa-lg"></i> linkedin</a></li>
</ul>
</li>
<li class="list-group-item"><h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Popular posts</span></h4>
<ul class="list-group" id="popularposts">
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="index.html">
Let's Build A Web Server. Part 1.
</a>
</li>
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="../lsbasi-part1/index.html">
Let's Build A Simple Interpreter. Part 1.
</a>
</li>
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="../lsbaws-part2/index.html">
Let's Build A Web Server. Part 2.
</a>
</li>
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="../lsbaws-part3/index.html">
Let's Build A Web Server. Part 3.
</a>
</li>
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="../lsbasi-part2/index.html">
Let's Build A Simple Interpreter. Part 2.
</a>
</li>
</ul>
</li>
<li class="list-group-item">
<h4>
<span>Disclaimer</span>
</h4>
<p id="disclaimer-text"> Some of the links on this site
have my Amazon referral id, which provides me with a small
commission for each sale. Thank you for your support.
</p>
</li>
</ul>
</section>
</aside>
</div>
</div>
</div>
<footer>
<div class="container">
<hr>
<div class="row">
<div class="col-xs-10">&copy; 2020 Ruslan Spivak
<!-- &middot; Powered by <a href="https://github.com/DandyDev/pelican-bootstrap3" target="_blank">pelican-bootstrap3</a>, -->
<!-- <a href="http://docs.getpelican.com/" target="_blank">Pelican</a>, -->
<!-- <a href="http://getbootstrap.com" target="_blank">Bootstrap</a> -->
<!-- -->
</div>
<div class="col-xs-2"><p class="pull-right"><i class="fa fa-arrow-up"></i> <a href="index.html#">Back to top</a></p></div>
</div>
</div>
</footer>
<script src="../theme/js/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="../theme/js/bootstrap.min.js"></script>
<!-- Enable responsive features in IE8 with Respond.js (https://github.com/scottjehl/Respond) -->
<script src="../theme/js/respond.min.js"></script>
<!-- Disqus -->
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'ruslanspivak'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function () {
var s = document.createElement('script');
s.async = true;
s.type = 'text/javascript';
s.src = '//' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
<!-- End Disqus Code -->
<!-- Google Analytics Universal -->
<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-2572871-3', 'auto');
ga('send', 'pageview');
</script>
<!-- End Google Analytics Universal Code -->
</body>
</html>