Create gh-pages branch via GitHub

This commit is contained in:
Me No Dev 2016-04-25 13:49:08 +03:00
commit 7100994fc9
5 changed files with 1446 additions and 0 deletions

647
index.html Normal file
View File

@ -0,0 +1,647 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>ESPAsyncWebServer by me-no-dev</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/normalize.css" media="screen">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/github-light.css" media="screen">
</head>
<body>
<section class="page-header">
<h1 class="project-name">ESPAsyncWebServer</h1>
<h2 class="project-tagline">Async HTTP and WebSocket Server for ESP8266 and ESP32 Arduino</h2>
<a href="https://github.com/me-no-dev/ESPAsyncWebServer" class="btn">View on GitHub</a>
<a href="https://github.com/me-no-dev/ESPAsyncWebServer/zipball/master" class="btn">Download .zip</a>
<a href="https://github.com/me-no-dev/ESPAsyncWebServer/tarball/master" class="btn">Download .tar.gz</a>
</section>
<section class="main-content">
<h1>
<a id="espasyncwebserver" class="anchor" href="#espasyncwebserver" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>ESPAsyncWebServer</h1>
<p>Async HTTP and WebSocket Server for ESP8266 and ESP32/ESP31B Arduino</p>
<p>Requires <a href="https://github.com/me-no-dev/ESPAsyncTCP">ESPAsyncTCP</a> to work</p>
<h2>
<a id="why-should-you-care" class="anchor" href="#why-should-you-care" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Why should you care</h2>
<ul>
<li>Using asynchronous network means that you can handle more than one connection at the same time</li>
<li>You are called once the request is ready and parsed</li>
<li>When you send the response, you are immediately ready to handle other connections
while the server is taking care of sending the response in the background</li>
<li>Speed is OMG</li>
<li>Easy to use API, HTTP Basic Authentication, ChunkedResponse</li>
<li>Easily extendible to handle any type of content</li>
<li>Supports Continue 100</li>
<li>Async WebSocket plugin offering different locations without extra servers or ports</li>
</ul>
<h2>
<a id="important-things-to-remember" class="anchor" href="#important-things-to-remember" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Important things to remember</h2>
<ul>
<li>This is fully asynchronous server and as such does not run on the loop thread.</li>
<li>You can not use yield or delay or any function that uses them inside the callbacks</li>
<li>The server is smart enough to know when to close the connection and free resources</li>
<li>You can not send more than one response to a single request</li>
</ul>
<h2>
<a id="principles-of-operation" class="anchor" href="#principles-of-operation" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Principles of operation</h2>
<h3>
<a id="the-async-web-server" class="anchor" href="#the-async-web-server" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>The Async Web server</h3>
<ul>
<li>Listens for connections</li>
<li>Wraps the new clients into <code>Request</code>
</li>
<li>Keeps track of clients and cleans memory</li>
<li>Manages <code>Handlers</code> and attaches them to Requests</li>
</ul>
<h3>
<a id="request-life-cycle" class="anchor" href="#request-life-cycle" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Request Life Cycle</h3>
<ul>
<li>TCP connection is received by the server</li>
<li>The connection is wrapped inside <code>Request</code> object</li>
<li>When the request head is received (type, url, get params, http version and host),
the server goes through all attached <code>Handlers</code>(in the order they are attached) trying to find one
that <code>canHandle</code> the given request. If none are found, the default(catch-all) handler is attached.</li>
<li>The rest of the request is received, calling the <code>handleUpload</code> or <code>handleBody</code> methods of the <code>Handler</code> if they are needed (POST+File/Body)</li>
<li>When the whole request is parsed, the result is given to the <code>handleRequest</code> method of the <code>Handler</code> and is ready to be responded to</li>
<li>In the <code>handleRequest</code> method, to the <code>Request</code> is attached a <code>Response</code> object (see below) that will serve the response data back to the client</li>
<li>When the <code>Response</code> is sent, the client is closed and freed from the memory</li>
</ul>
<h3>
<a id="handlers-and-how-do-they-work" class="anchor" href="#handlers-and-how-do-they-work" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Handlers and how do they work</h3>
<ul>
<li>The <code>Handlers</code> are used for executing specific actions to particular requests</li>
<li>One <code>Handler</code> instance can be attached to any request and lives together with the server</li>
<li>The <code>canHandle</code> method is used for filtering the requests that can be handled
and declaring any interesting headers that the <code>Request</code> should collect </li>
<li>Decision can be based on request method, request url, http version, request host/port/target host and GET parameters</li>
<li>Once a <code>Handler</code> is attached to given <code>Request</code> (<code>canHandle</code> returned true)
that <code>Handler</code> takes care to receive any file/data upload and attach a <code>Response</code>
once the <code>Request</code> has been fully parsed</li>
<li>
<code>Handler's</code> <code>canHandle</code> is called in the order they are attached to the server.
If a <code>Handler</code> attached earlier returns <code>true</code> on <code>canHandle</code>, then this <code>Hander's</code> <code>canHandle</code> will never be called</li>
</ul>
<h3>
<a id="responses-and-how-do-they-work" class="anchor" href="#responses-and-how-do-they-work" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Responses and how do they work</h3>
<ul>
<li>The <code>Response</code> objects are used to send the response data back to the client</li>
<li>The <code>Response</code> object lives with the <code>Request</code> and is freed on end or disconnect</li>
<li>Different techniques are used depending on the response type to send the data in packets
returning back almost immediately and sending the next packet when this one is received.
Any time in between is spent to run the user loop and handle other network packets</li>
<li>Responding asynchronously is probably the most difficult thing for most to understand</li>
<li>Many different options exist for the user to make responding a background task</li>
</ul>
<h2>
<a id="request-variables" class="anchor" href="#request-variables" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Request Variables</h2>
<h3>
<a id="common-variables" class="anchor" href="#common-variables" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Common Variables</h3>
<div class="highlight highlight-source-c++"><pre>request-&gt;<span class="pl-en">version</span>(); <span class="pl-c">// uint8_t: 0 = HTTP/1.0, 1 = HTTP/1.1</span>
request-&gt;<span class="pl-en">method</span>(); <span class="pl-c">// enum: HTTP_GET, HTTP_POST, HTTP_DELETE, HTTP_PUT, HTTP_PATCH, HTTP_HEAD, HTTP_OPTIONS</span>
request-&gt;<span class="pl-en">url</span>(); <span class="pl-c">// String: URL of the request (not including host, port or GET parameters) </span>
request-&gt;<span class="pl-en">host</span>(); <span class="pl-c">// String: The requested host (can be used for virtual hosting)</span>
request-&gt;<span class="pl-en">contentType</span>(); <span class="pl-c">// String: ContentType of the request (not avaiable in Handler::canHandle)</span>
request-&gt;<span class="pl-en">contentLength</span>(); <span class="pl-c">// size_t: ContentLength of the request (not avaiable in Handler::canHandle)</span>
request-&gt;<span class="pl-en">multipart</span>(); <span class="pl-c">// bool: True if the request has content type "multipart"</span></pre></div>
<h3>
<a id="headers" class="anchor" href="#headers" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Headers</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//List all collected headers</span>
<span class="pl-k">int</span> headers = request-&gt;<span class="pl-en">headers</span>();
<span class="pl-k">int</span> i;
<span class="pl-k">for</span>(i=<span class="pl-c1">0</span>;i&lt;headers;i++){
AsyncWebHeader* h = request-&gt;<span class="pl-c1">getHeader</span>(i);
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>HEADER[<span class="pl-c1">%s</span>]: <span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, h-&gt;<span class="pl-c1">name</span>().<span class="pl-c1">c_str</span>(), h-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>());
}
<span class="pl-c">//get specific header by name</span>
<span class="pl-k">if</span>(request-&gt;<span class="pl-en">hasHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>MyHeader<span class="pl-pds">"</span></span>)){
AsyncWebHeader* h = request-&gt;<span class="pl-c1">getHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>MyHeader<span class="pl-pds">"</span></span>);
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>MyHeader: <span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, h-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>());
}</pre></div>
<h3>
<a id="get-post-and-file-parameters" class="anchor" href="#get-post-and-file-parameters" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>GET, POST and FILE parameters</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//List all parameters</span>
<span class="pl-k">int</span> params = request-&gt;<span class="pl-en">params</span>();
<span class="pl-k">for</span>(<span class="pl-k">int</span> i=<span class="pl-c1">0</span>;i&lt;params;i++){
AsyncWebParameter* p = request-&gt;<span class="pl-c1">getParam</span>(i);
<span class="pl-k">if</span>(p-&gt;<span class="pl-c1">isFile</span>()){ <span class="pl-c">//p-&gt;isPost() is also true</span>
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>FILE[<span class="pl-c1">%s</span>]: <span class="pl-c1">%s</span>, size: <span class="pl-c1">%u</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, p-&gt;<span class="pl-c1">name</span>().<span class="pl-c1">c_str</span>(), p-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>(), p-&gt;<span class="pl-c1">size</span>());
} <span class="pl-k">else</span> <span class="pl-k">if</span>(p-&gt;<span class="pl-c1">isPost</span>()){
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>POST[<span class="pl-c1">%s</span>]: <span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, p-&gt;<span class="pl-c1">name</span>().<span class="pl-c1">c_str</span>(), p-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>());
} <span class="pl-k">else</span> {
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>GET[<span class="pl-c1">%s</span>]: <span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, p-&gt;<span class="pl-c1">name</span>().<span class="pl-c1">c_str</span>(), p-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>());
}
}
<span class="pl-c">//Check if GET parameter exists</span>
<span class="pl-k">bool</span> exists = request-&gt;<span class="pl-en">hasParam</span>(<span class="pl-s"><span class="pl-pds">"</span>download<span class="pl-pds">"</span></span>);
AsyncWebParameter* p = request-&gt;<span class="pl-en">getParam</span>(<span class="pl-s"><span class="pl-pds">"</span>download<span class="pl-pds">"</span></span>);
<span class="pl-c">//Check if POST (but not File) parameter exists</span>
<span class="pl-k">bool</span> exists = request-&gt;<span class="pl-en">hasParam</span>(<span class="pl-s"><span class="pl-pds">"</span>download<span class="pl-pds">"</span></span>, <span class="pl-c1">true</span>);
AsyncWebParameter* p = request-&gt;<span class="pl-en">getParam</span>(<span class="pl-s"><span class="pl-pds">"</span>download<span class="pl-pds">"</span></span>, <span class="pl-c1">true</span>);
<span class="pl-c">//Check if FILE was uploaded</span>
<span class="pl-k">bool</span> exists = request-&gt;<span class="pl-en">hasParam</span>(<span class="pl-s"><span class="pl-pds">"</span>download<span class="pl-pds">"</span></span>, <span class="pl-c1">true</span>, <span class="pl-c1">true</span>);
AsyncWebParameter* p = request-&gt;<span class="pl-en">getParam</span>(<span class="pl-s"><span class="pl-pds">"</span>download<span class="pl-pds">"</span></span>, <span class="pl-c1">true</span>, <span class="pl-c1">true</span>);</pre></div>
<h3>
<a id="file-upload-handling" class="anchor" href="#file-upload-handling" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>FILE Upload handling</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-k">void</span> <span class="pl-en">handleUpload</span>(AsyncWebServerRequest *request, String filename, <span class="pl-c1">size_t</span> index, <span class="pl-c1">uint8_t</span> *data, <span class="pl-c1">size_t</span> len, <span class="pl-k">bool</span> final){
<span class="pl-k">if</span>(!<span class="pl-c1">index</span>){
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>UploadStart: <span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, filename.<span class="pl-c1">c_str</span>());
}
<span class="pl-k">for</span>(<span class="pl-c1">size_t</span> i=<span class="pl-c1">0</span>; i&lt;len; i++){
Serial.<span class="pl-c1">write</span>(data[i]);
}
<span class="pl-k">if</span>(final){
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>UploadEnd: <span class="pl-c1">%s</span>, <span class="pl-c1">%u</span> B<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, filename.<span class="pl-c1">c_str</span>(), <span class="pl-c1">index</span>+len);
}
}</pre></div>
<h3>
<a id="body-data-handling" class="anchor" href="#body-data-handling" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Body data handling</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-k">void</span> <span class="pl-en">handleBody</span>(AsyncWebServerRequest *request, <span class="pl-c1">uint8_t</span> *data, <span class="pl-c1">size_t</span> len, <span class="pl-c1">size_t</span> index, <span class="pl-c1">size_t</span> total){
<span class="pl-k">if</span>(!<span class="pl-c1">index</span>){
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>BodyStart: <span class="pl-c1">%u</span> B<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, total);
}
<span class="pl-k">for</span>(<span class="pl-c1">size_t</span> i=<span class="pl-c1">0</span>; i&lt;len; i++){
Serial.<span class="pl-c1">write</span>(data[i]);
}
<span class="pl-k">if</span>(<span class="pl-c1">index</span> + len == total){
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>BodyEnd: <span class="pl-c1">%u</span> B<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, total);
}
}</pre></div>
<h2>
<a id="responses" class="anchor" href="#responses" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Responses</h2>
<h3>
<a id="basic-response-with-http-code" class="anchor" href="#basic-response-with-http-code" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Basic response with HTTP Code</h3>
<div class="highlight highlight-source-c++"><pre>request-&gt;<span class="pl-en">send</span>(<span class="pl-c1">404</span>); <span class="pl-c">//Sends 404 File Not Found</span></pre></div>
<h3>
<a id="basic-response-with-http-code-and-extra-headers" class="anchor" href="#basic-response-with-http-code-and-extra-headers" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Basic response with HTTP Code and extra headers</h3>
<div class="highlight highlight-source-c++"><pre>AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginResponse</span>(<span class="pl-c1">404</span>); <span class="pl-c">//Sends 404 File Not Found</span>
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>,<span class="pl-s"><span class="pl-pds">"</span>ESP Async Web Server<span class="pl-pds">"</span></span>);
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h3>
<a id="basic-response-with-string-content" class="anchor" href="#basic-response-with-string-content" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Basic response with string content</h3>
<div class="highlight highlight-source-c++"><pre>request-&gt;<span class="pl-en">send</span>(<span class="pl-c1">200</span>, <span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>Hello World!<span class="pl-pds">"</span></span>);</pre></div>
<h3>
<a id="basic-response-with-string-content-and-extra-headers" class="anchor" href="#basic-response-with-string-content-and-extra-headers" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Basic response with string content and extra headers</h3>
<div class="highlight highlight-source-c++"><pre>AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginResponse</span>(<span class="pl-c1">200</span>, <span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>Hello World!<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>,<span class="pl-s"><span class="pl-pds">"</span>ESP Async Web Server<span class="pl-pds">"</span></span>);
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h3>
<a id="respond-with-content-coming-from-a-stream" class="anchor" href="#respond-with-content-coming-from-a-stream" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Respond with content coming from a Stream</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//read 12 bytes from Serial and send them as Content Type text/plain</span>
request-&gt;<span class="pl-en">send</span>(Serial, <span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-c1">12</span>);</pre></div>
<h3>
<a id="respond-with-content-coming-from-a-stream-and-extra-headers" class="anchor" href="#respond-with-content-coming-from-a-stream-and-extra-headers" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Respond with content coming from a Stream and extra headers</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//read 12 bytes from Serial and send them as Content Type text/plain</span>
AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginResponse</span>(Serial, <span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-c1">12</span>);
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>,<span class="pl-s"><span class="pl-pds">"</span>ESP Async Web Server<span class="pl-pds">"</span></span>);
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h3>
<a id="respond-with-content-coming-from-a-file" class="anchor" href="#respond-with-content-coming-from-a-file" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Respond with content coming from a File</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//Send index.htm with default content type</span>
request-&gt;<span class="pl-en">send</span>(SPIFFS, <span class="pl-s"><span class="pl-pds">"</span>/index.htm<span class="pl-pds">"</span></span>);
<span class="pl-c">//Send index.htm as text</span>
request-&gt;<span class="pl-en">send</span>(SPIFFS, <span class="pl-s"><span class="pl-pds">"</span>/index.htm<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>);
<span class="pl-c">//Download index.htm</span>
request-&gt;<span class="pl-en">send</span>(SPIFFS, <span class="pl-s"><span class="pl-pds">"</span>/index.htm<span class="pl-pds">"</span></span>, String(), true);</pre></div>
<h3>
<a id="respond-with-content-coming-from-a-file-and-extra-headers" class="anchor" href="#respond-with-content-coming-from-a-file-and-extra-headers" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Respond with content coming from a File and extra headers</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//Send index.htm with default content type</span>
AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginResponse</span>(SPIFFS, <span class="pl-s"><span class="pl-pds">"</span>/index.htm<span class="pl-pds">"</span></span>);
<span class="pl-c">//Send index.htm as text</span>
AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginResponse</span>(SPIFFS, <span class="pl-s"><span class="pl-pds">"</span>/index.htm<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>);
<span class="pl-c">//Download index.htm</span>
AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginResponse</span>(SPIFFS, <span class="pl-s"><span class="pl-pds">"</span>/index.htm<span class="pl-pds">"</span></span>, String(), true);
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>,<span class="pl-s"><span class="pl-pds">"</span>ESP Async Web Server<span class="pl-pds">"</span></span>);
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h3>
<a id="respond-with-content-using-a-callback" class="anchor" href="#respond-with-content-using-a-callback" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Respond with content using a callback</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//send 128 bytes as plain text</span>
request-&gt;<span class="pl-en">send</span>(<span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-c1">128</span>, [](<span class="pl-c1">uint8_t</span> *buffer, <span class="pl-c1">size_t</span> maxLen, <span class="pl-c1">size_t</span> index) -&gt; size_t {
<span class="pl-c">//Write up to "maxLen" bytes into "buffer" and return the amount written.</span>
<span class="pl-c">//index equals the amount of bytes that have been already sent</span>
<span class="pl-c">//You will not be asked for more bytes once the content length has been reached.</span>
<span class="pl-c">//Keep in mind that you can not delay or yield waiting for more data!</span>
<span class="pl-c">//Send what you currently have and you will be asked for more again</span>
<span class="pl-k">return</span> mySource.<span class="pl-c1">read</span>(buffer, maxLen);
});</pre></div>
<h3>
<a id="respond-with-content-using-a-callback-and-extra-headers" class="anchor" href="#respond-with-content-using-a-callback-and-extra-headers" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Respond with content using a callback and extra headers</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//send 128 bytes as plain text</span>
AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginResponse</span>(<span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-c1">128</span>, [](<span class="pl-c1">uint8_t</span> *buffer, <span class="pl-c1">size_t</span> maxLen, <span class="pl-c1">size_t</span> index) -&gt; size_t {
<span class="pl-c">//Write up to "maxLen" bytes into "buffer" and return the amount written.</span>
<span class="pl-c">//index equals the amount of bytes that have been already sent</span>
<span class="pl-c">//You will not be asked for more bytes once the content length has been reached.</span>
<span class="pl-c">//Keep in mind that you can not delay or yield waiting for more data!</span>
<span class="pl-c">//Send what you currently have and you will be asked for more again</span>
<span class="pl-k">return</span> mySource.<span class="pl-c1">read</span>(buffer, maxLen);
});
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>,<span class="pl-s"><span class="pl-pds">"</span>ESP Async Web Server<span class="pl-pds">"</span></span>);
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h3>
<a id="chunked-response" class="anchor" href="#chunked-response" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Chunked Response</h3>
<p>Used when content length is unknown. Works best if the client supports HTTP/1.1</p>
<div class="highlight highlight-source-c++"><pre>AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginChunkedResponse</span>(<span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, [](<span class="pl-c1">uint8_t</span> *buffer, <span class="pl-c1">size_t</span> maxLen, <span class="pl-c1">size_t</span> index) -&gt; size_t {
<span class="pl-c">//Write up to "maxLen" bytes into "buffer" and return the amount written.</span>
<span class="pl-c">//index equals the amount of bytes that have been already sent</span>
<span class="pl-c">//You will be asked for more data until 0 is returned</span>
<span class="pl-c">//Keep in mind that you can not delay or yield waiting for more data!</span>
<span class="pl-k">return</span> mySource.<span class="pl-c1">read</span>(buffer, maxLen);
});
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>,<span class="pl-s"><span class="pl-pds">"</span>ESP Async Web Server<span class="pl-pds">"</span></span>);
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h3>
<a id="print-to-response" class="anchor" href="#print-to-response" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Print to response</h3>
<div class="highlight highlight-source-c++"><pre>AsyncResponseStream *response = request-&gt;<span class="pl-en">beginResponseStream</span>(<span class="pl-s"><span class="pl-pds">"</span>text/html<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>,<span class="pl-s"><span class="pl-pds">"</span>ESP Async Web Server<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;title&gt;Webpage at <span class="pl-c1">%s</span>&lt;/title&gt;&lt;/head&gt;&lt;body&gt;<span class="pl-pds">"</span></span>, request-&gt;<span class="pl-en">url</span>().c_str());
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;h2&gt;Hello <span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">print</span>(request-&gt;<span class="pl-en">client</span>()-&gt;remoteIP());
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;/h2&gt;<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;h3&gt;General&lt;/h3&gt;<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;ul&gt;<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;Version: HTTP/1.<span class="pl-c1">%u</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, request-&gt;<span class="pl-en">version</span>());
response-&gt;<span class="pl-en">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;Method: <span class="pl-c1">%s</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, request-&gt;<span class="pl-en">methodToString</span>());
response-&gt;<span class="pl-en">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;URL: <span class="pl-c1">%s</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, request-&gt;<span class="pl-en">url</span>().c_str());
response-&gt;<span class="pl-en">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;Host: <span class="pl-c1">%s</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, request-&gt;<span class="pl-en">host</span>().c_str());
response-&gt;<span class="pl-en">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;ContentType: <span class="pl-c1">%s</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, request-&gt;<span class="pl-en">contentType</span>().c_str());
response-&gt;<span class="pl-en">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;ContentLength: <span class="pl-c1">%u</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, request-&gt;<span class="pl-en">contentLength</span>());
response-&gt;<span class="pl-en">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;Multipart: <span class="pl-c1">%s</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, request-&gt;<span class="pl-en">multipart</span>()?"true":"false");
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;/ul&gt;<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;h3&gt;Headers&lt;/h3&gt;<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;ul&gt;<span class="pl-pds">"</span></span>);
<span class="pl-k">int</span> headers = request-&gt;<span class="pl-en">headers</span>();
<span class="pl-k">for</span>(<span class="pl-k">int</span> i=<span class="pl-c1">0</span>;i&lt;headers;i++){
AsyncWebHeader* h = request-&gt;<span class="pl-c1">getHeader</span>(i);
response-&gt;<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;<span class="pl-c1">%s</span>: <span class="pl-c1">%s</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, h-&gt;<span class="pl-c1">name</span>().<span class="pl-c1">c_str</span>(), h-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>());
}
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;/ul&gt;<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;h3&gt;Parameters&lt;/h3&gt;<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;ul&gt;<span class="pl-pds">"</span></span>);
<span class="pl-k">int</span> params = request-&gt;<span class="pl-en">params</span>();
<span class="pl-k">for</span>(<span class="pl-k">int</span> i=<span class="pl-c1">0</span>;i&lt;params;i++){
AsyncWebParameter* p = request-&gt;<span class="pl-c1">getParam</span>(i);
<span class="pl-k">if</span>(p-&gt;<span class="pl-c1">isFile</span>()){
response-&gt;<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;FILE[<span class="pl-c1">%s</span>]: <span class="pl-c1">%s</span>, size: <span class="pl-c1">%u</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, p-&gt;<span class="pl-c1">name</span>().<span class="pl-c1">c_str</span>(), p-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>(), p-&gt;<span class="pl-c1">size</span>());
} <span class="pl-k">else</span> <span class="pl-k">if</span>(p-&gt;<span class="pl-c1">isPost</span>()){
response-&gt;<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;POST[<span class="pl-c1">%s</span>]: <span class="pl-c1">%s</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, p-&gt;<span class="pl-c1">name</span>().<span class="pl-c1">c_str</span>(), p-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>());
} <span class="pl-k">else</span> {
response-&gt;<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;li&gt;GET[<span class="pl-c1">%s</span>]: <span class="pl-c1">%s</span>&lt;/li&gt;<span class="pl-pds">"</span></span>, p-&gt;<span class="pl-c1">name</span>().<span class="pl-c1">c_str</span>(), p-&gt;<span class="pl-c1">value</span>().<span class="pl-c1">c_str</span>());
}
}
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;/ul&gt;<span class="pl-pds">"</span></span>);
response-&gt;<span class="pl-en">print</span>(<span class="pl-s"><span class="pl-pds">"</span>&lt;/body&gt;&lt;/html&gt;<span class="pl-pds">"</span></span>);
<span class="pl-c">//send the response last</span>
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h3>
<a id="send-a-large-webpage-from-progmem-using-callback-response" class="anchor" href="#send-a-large-webpage-from-progmem-using-callback-response" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Send a large webpage from PROGMEM using callback response</h3>
<p>Example provided by <a href="https://github.com/nouser2013">@nouser2013</a></p>
<div class="highlight highlight-source-c++"><pre><span class="pl-k">const</span> <span class="pl-k">char</span> indexhtml[] PROGMEM = <span class="pl-s"><span class="pl-pds">"</span>...<span class="pl-pds">"</span></span>; <span class="pl-c">// large char array, tested with 5k</span>
AsyncWebServerResponse *response = request-&gt;<span class="pl-en">beginResponse</span>(
<span class="pl-en">String</span>(<span class="pl-s"><span class="pl-pds">"</span>text/html<span class="pl-pds">"</span></span>),
strlen_P(indexhtml),
[](<span class="pl-c1">uint8_t</span> *buffer, <span class="pl-c1">size_t</span> maxLen, <span class="pl-c1">size_t</span> alreadySent) -&gt; size_t {
<span class="pl-k">if</span> (<span class="pl-c1">strlen_P</span>(indexhtml+alreadySent)&gt;maxLen) {
<span class="pl-c">// We have more to read than fits in maxLen Buffer</span>
<span class="pl-c1">memcpy_P</span>((<span class="pl-k">char</span>*)buffer, indexhtml+alreadySent, maxLen);
<span class="pl-k">return</span> maxLen;
}
<span class="pl-c">// Ok, last chunk</span>
<span class="pl-c1">memcpy_P</span>((<span class="pl-k">char</span>*)buffer, indexhtml+alreadySent, <span class="pl-c1">strlen_P</span>(indexhtml+alreadySent));
<span class="pl-k">return</span> <span class="pl-c1">strlen_P</span>(indexhtml+alreadySent); <span class="pl-c">// Return from here to end of indexhtml</span>
}
);
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>MyServerString<span class="pl-pds">"</span></span>);
request-&gt;<span class="pl-en">send</span>(response); </pre></div>
<h3>
<a id="arduinojson-basic-response" class="anchor" href="#arduinojson-basic-response" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>ArduinoJson Basic Response</h3>
<p>This way of sending Json is great for when the result is below 4KB </p>
<div class="highlight highlight-source-c++"><pre>#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>AsyncJson.h<span class="pl-pds">"</span></span>
#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>ArduinoJson.h<span class="pl-pds">"</span></span>
AsyncResponseStream *response = request-&gt;<span class="pl-en">beginResponseStream</span>(<span class="pl-s"><span class="pl-pds">"</span>text/json<span class="pl-pds">"</span></span>);
DynamicJsonBuffer jsonBuffer;
JsonObject &amp;root = jsonBuffer.createObject();
root[<span class="pl-s"><span class="pl-pds">"</span>heap<span class="pl-pds">"</span></span>] = ESP.getFreeHeap();
root[<span class="pl-s"><span class="pl-pds">"</span>ssid<span class="pl-pds">"</span></span>] = WiFi.SSID();
root.printTo(*response);
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h3>
<a id="arduinojson-advanced-response" class="anchor" href="#arduinojson-advanced-response" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>ArduinoJson Advanced Response</h3>
<p>This response can handle really large Json objects (tested to 40KB)
There isn't any noticeable speed decrease for small results with the method above
Since ArduinoJson does not allow reading parts of the string, the whole Json has to
be passed every time a chunks needs to be sent, which shows speed decrease proportional
to the resulting json packets</p>
<div class="highlight highlight-source-c++"><pre>#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>AsyncJson.h<span class="pl-pds">"</span></span>
#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>ArduinoJson.h<span class="pl-pds">"</span></span>
AsyncJsonResponse * response = <span class="pl-k">new</span> AsyncJsonResponse();
response-&gt;<span class="pl-en">addHeader</span>(<span class="pl-s"><span class="pl-pds">"</span>Server<span class="pl-pds">"</span></span>,<span class="pl-s"><span class="pl-pds">"</span>ESP Async Web Server<span class="pl-pds">"</span></span>);
JsonObject&amp; root = response-&gt;<span class="pl-en">getRoot</span>();
root[<span class="pl-s"><span class="pl-pds">"</span>heap<span class="pl-pds">"</span></span>] = ESP.getFreeHeap();
root[<span class="pl-s"><span class="pl-pds">"</span>ssid<span class="pl-pds">"</span></span>] = WiFi.SSID();
response-&gt;<span class="pl-en">setLength</span>();
request-&gt;<span class="pl-en">send</span>(response);</pre></div>
<h2>
<a id="bad-responses" class="anchor" href="#bad-responses" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Bad Responses</h2>
<p>Some responses are implemented, but you should not use them, because they do not conform to HTTP.
The following example will lead to unclean close of the connection and more time wasted
than providing the length of the content</p>
<h3>
<a id="respond-with-content-using-a-callback-without-content-length-to-http10-clients" class="anchor" href="#respond-with-content-using-a-callback-without-content-length-to-http10-clients" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Respond with content using a callback without content length to HTTP/1.0 clients</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//This is used as fallback for chunked responses to HTTP/1.0 Clients</span>
request-&gt;<span class="pl-en">send</span>(<span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-c1">0</span>, [](<span class="pl-c1">uint8_t</span> *buffer, <span class="pl-c1">size_t</span> maxLen, <span class="pl-c1">size_t</span> index) -&gt; size_t {
<span class="pl-c">//Write up to "maxLen" bytes into "buffer" and return the amount written.</span>
<span class="pl-c">//You will be asked for more data until 0 is returned</span>
<span class="pl-c">//Keep in mind that you can not delay or yield waiting for more data!</span>
<span class="pl-k">return</span> mySource.<span class="pl-c1">read</span>(buffer, maxLen);
});</pre></div>
<h2>
<a id="async-websocket-plugin" class="anchor" href="#async-websocket-plugin" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Async WebSocket Plugin</h2>
<p>The server includes a web socket plugin which lets you define different WebSocket locations to connect to
without starting another listening service or using different port</p>
<h3>
<a id="async-websocket-event" class="anchor" href="#async-websocket-event" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Async WebSocket Event</h3>
<div class="highlight highlight-source-c++"><pre>
<span class="pl-k">void</span> <span class="pl-en">onEvent</span>(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, <span class="pl-k">void</span> * arg, <span class="pl-c1">uint8_t</span> *data, <span class="pl-c1">size_t</span> len){
<span class="pl-k">if</span>(type == WS_EVT_CONNECT){
<span class="pl-c">//client connected</span>
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] connect<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>());
client-&gt;<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>Hello Client <span class="pl-c1">%u</span> :)<span class="pl-pds">"</span></span>, client-&gt;<span class="pl-c1">id</span>());
client-&gt;<span class="pl-c1">ping</span>();
} <span class="pl-k">else</span> <span class="pl-k">if</span>(type == WS_EVT_DISCONNECT){
<span class="pl-c">//client disconnected</span>
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] disconnect: <span class="pl-c1">%u</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>());
} <span class="pl-k">else</span> <span class="pl-k">if</span>(type == WS_EVT_ERROR){
<span class="pl-c">//error was received from the other end</span>
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] error(<span class="pl-c1">%u</span>): <span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>(), *((<span class="pl-c1">uint16_t</span>*)arg), (<span class="pl-k">char</span>*)data);
} <span class="pl-k">else</span> <span class="pl-k">if</span>(type == WS_EVT_PONG){
<span class="pl-c">//pong message was received (in response to a ping request maybe)</span>
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] pong[<span class="pl-c1">%u</span>]: <span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>(), len, (len)?(<span class="pl-k">char</span>*)data:<span class="pl-s"><span class="pl-pds">"</span><span class="pl-pds">"</span></span>);
} <span class="pl-k">else</span> <span class="pl-k">if</span>(type == WS_EVT_DATA){
<span class="pl-c">//data packet</span>
AwsFrameInfo * info = (AwsFrameInfo*)arg;
<span class="pl-k">if</span>(info-&gt;num == <span class="pl-c1">0</span> &amp;&amp; info-&gt;final &amp;&amp; info-&gt;<span class="pl-c1">index</span> == <span class="pl-c1">0</span> &amp;&amp; info-&gt;len == len){
<span class="pl-c">//the whole message is in a single frame and we got all of it's data</span>
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] <span class="pl-c1">%s</span>-message[<span class="pl-c1">%llu</span>]: <span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>(), (info-&gt;opcode == WS_TEXT)?<span class="pl-s"><span class="pl-pds">"</span>text<span class="pl-pds">"</span></span>:<span class="pl-s"><span class="pl-pds">"</span>binary<span class="pl-pds">"</span></span>, info-&gt;len);
<span class="pl-k">if</span>(info-&gt;opcode == WS_TEXT){
data[len] = <span class="pl-c1">0</span>;
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span><span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, (<span class="pl-k">char</span>*)data);
} <span class="pl-k">else</span> {
<span class="pl-k">for</span>(<span class="pl-c1">size_t</span> i=<span class="pl-c1">0</span>; i &lt; info-&gt;len; i++){
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span><span class="pl-c1">%02x</span> <span class="pl-pds">"</span></span>, data[i]);
}
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>);
}
<span class="pl-k">if</span>(info-&gt;opcode == WS_TEXT)
client-&gt;<span class="pl-c1">text</span>(<span class="pl-s"><span class="pl-pds">"</span>I got your text message<span class="pl-pds">"</span></span>);
<span class="pl-k">else</span>
client-&gt;<span class="pl-c1">binary</span>(<span class="pl-s"><span class="pl-pds">"</span>I got your binary message<span class="pl-pds">"</span></span>);
} <span class="pl-k">else</span> {
<span class="pl-c">//message is comprised of multiple frames or the frame is split into multiple packets</span>
<span class="pl-k">if</span>(info-&gt;<span class="pl-c1">index</span> == <span class="pl-c1">0</span>){
<span class="pl-k">if</span>(info-&gt;num == <span class="pl-c1">0</span>)
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] <span class="pl-c1">%s</span>-message start<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>(), (info-&gt;message_opcode == WS_TEXT)?<span class="pl-s"><span class="pl-pds">"</span>text<span class="pl-pds">"</span></span>:<span class="pl-s"><span class="pl-pds">"</span>binary<span class="pl-pds">"</span></span>);
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] frame[<span class="pl-c1">%u</span>] start[<span class="pl-c1">%llu</span>]<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>(), info-&gt;num, info-&gt;len);
}
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] frame[<span class="pl-c1">%u</span>] <span class="pl-c1">%s</span>[<span class="pl-c1">%llu</span> - <span class="pl-c1">%llu</span>]: <span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>(), info-&gt;num, (info-&gt;message_opcode == WS_TEXT)?<span class="pl-s"><span class="pl-pds">"</span>text<span class="pl-pds">"</span></span>:<span class="pl-s"><span class="pl-pds">"</span>binary<span class="pl-pds">"</span></span>, info-&gt;<span class="pl-c1">index</span>, info-&gt;<span class="pl-c1">index</span> + len);
<span class="pl-k">if</span>(info-&gt;message_opcode == WS_TEXT){
data[len] = <span class="pl-c1">0</span>;
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span><span class="pl-c1">%s</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, (<span class="pl-k">char</span>*)data);
} <span class="pl-k">else</span> {
<span class="pl-k">for</span>(<span class="pl-c1">size_t</span> i=<span class="pl-c1">0</span>; i &lt; len; i++){
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span><span class="pl-c1">%02x</span> <span class="pl-pds">"</span></span>, data[i]);
}
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span><span class="pl-cce">\n</span><span class="pl-pds">"</span></span>);
}
<span class="pl-k">if</span>((info-&gt;<span class="pl-c1">index</span> + len) == info-&gt;len){
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] frame[<span class="pl-c1">%u</span>] end[<span class="pl-c1">%llu</span>]<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>(), info-&gt;num, info-&gt;len);
<span class="pl-k">if</span>(info-&gt;final){
<span class="pl-c1">os_printf</span>(<span class="pl-s"><span class="pl-pds">"</span>ws[<span class="pl-c1">%s</span>][<span class="pl-c1">%u</span>] <span class="pl-c1">%s</span>-message end<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>, server-&gt;<span class="pl-c1">url</span>(), client-&gt;<span class="pl-c1">id</span>(), (info-&gt;message_opcode == WS_TEXT)?<span class="pl-s"><span class="pl-pds">"</span>text<span class="pl-pds">"</span></span>:<span class="pl-s"><span class="pl-pds">"</span>binary<span class="pl-pds">"</span></span>);
<span class="pl-k">if</span>(info-&gt;message_opcode == WS_TEXT)
client-&gt;<span class="pl-c1">text</span>(<span class="pl-s"><span class="pl-pds">"</span>I got your text message<span class="pl-pds">"</span></span>);
<span class="pl-k">else</span>
client-&gt;<span class="pl-c1">binary</span>(<span class="pl-s"><span class="pl-pds">"</span>I got your binary message<span class="pl-pds">"</span></span>);
}
}
}
}
}</pre></div>
<h3>
<a id="methods-for-sending-data-to-a-socket-client" class="anchor" href="#methods-for-sending-data-to-a-socket-client" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Methods for sending data to a socket client</h3>
<div class="highlight highlight-source-c++"><pre><span class="pl-c">//Server methods</span>
AsyncWebSocket <span class="pl-en">ws</span>(<span class="pl-s"><span class="pl-pds">"</span>/ws<span class="pl-pds">"</span></span>);
<span class="pl-c">//printf to a client</span>
ws.printf([client id], [arguments...])
<span class="pl-c">//printf to all clients</span>
ws.printfAll([arguments...])
<span class="pl-c">//send text to a client</span>
ws.text([client id], [(<span class="pl-k">char</span>*)text])
ws.text([client id], [text], [len])
<span class="pl-c">//send text to all clients</span>
ws.textAll([(<span class="pl-k">char</span>*text])
ws.textAll([text], [len])
<span class="pl-c">//send binary to a client</span>
ws.binary([client id], [(<span class="pl-k">char</span>*)binary])
ws.binary([client id], [binary], [len])
<span class="pl-c">//send binary to all clients</span>
ws.binaryAll([(<span class="pl-k">char</span>*binary])
ws.binaryAll([binary], [len])
<span class="pl-c">//client methods</span>
AsyncWebSocketClient * client;
<span class="pl-c">//printf to a client</span>
client-&gt;<span class="pl-en">printf</span>([arguments...])
<span class="pl-c">//send text to a client</span>
client-&gt;text([(<span class="pl-k">char</span>*)text])
client-&gt;text([text], [len])
<span class="pl-c">//send binary to a client</span>
client-&gt;binary([(<span class="pl-k">char</span>*)binary])
client-&gt;binary([binary], [len])
</pre></div>
<h2>
<a id="setting-up-the-server" class="anchor" href="#setting-up-the-server" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Setting up the server</h2>
<div class="highlight highlight-source-c++"><pre>#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>ESPAsyncTCP.h<span class="pl-pds">"</span></span>
#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>ESPAsyncWebServer.h<span class="pl-pds">"</span></span>
AsyncWebServer <span class="pl-en">server</span>(<span class="pl-c1">80</span>);
AsyncWebSocket <span class="pl-en">control_ws</span>(<span class="pl-s"><span class="pl-pds">"</span>/control<span class="pl-pds">"</span></span>); <span class="pl-c">// access at ws://[esp ip]/control</span>
AsyncWebSocket <span class="pl-en">data_ws</span>(<span class="pl-s"><span class="pl-pds">"</span>/data<span class="pl-pds">"</span></span>); <span class="pl-c">// access at ws://[esp ip]/data</span>
<span class="pl-k">const</span> <span class="pl-k">char</span>* ssid = <span class="pl-s"><span class="pl-pds">"</span>your-ssid<span class="pl-pds">"</span></span>;
<span class="pl-k">const</span> <span class="pl-k">char</span>* password = <span class="pl-s"><span class="pl-pds">"</span>your-pass<span class="pl-pds">"</span></span>;
<span class="pl-k">const</span> <span class="pl-k">char</span>* http_username = <span class="pl-s"><span class="pl-pds">"</span>admin<span class="pl-pds">"</span></span>;
<span class="pl-k">const</span> <span class="pl-k">char</span>* http_password = <span class="pl-s"><span class="pl-pds">"</span>admin<span class="pl-pds">"</span></span>;
<span class="pl-k">void</span> <span class="pl-en">onRequest</span>(AsyncWebServerRequest *request){
<span class="pl-c">//Handle Unknown Request</span>
request-&gt;<span class="pl-c1">send</span>(<span class="pl-c1">404</span>);
}
<span class="pl-k">void</span> <span class="pl-en">onBody</span>(AsyncWebServerRequest *request, <span class="pl-c1">uint8_t</span> *data, <span class="pl-c1">size_t</span> len, <span class="pl-c1">size_t</span> index, <span class="pl-c1">size_t</span> total){
<span class="pl-c">//Handle body</span>
}
<span class="pl-k">void</span> <span class="pl-en">onUpload</span>(AsyncWebServerRequest *request, String filename, <span class="pl-c1">size_t</span> index, <span class="pl-c1">uint8_t</span> *data, <span class="pl-c1">size_t</span> len, <span class="pl-k">bool</span> final){
<span class="pl-c">//Handle upload</span>
}
<span class="pl-k">void</span> <span class="pl-en">onEvent</span>(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, <span class="pl-k">void</span> * arg, <span class="pl-c1">uint8_t</span> *data, <span class="pl-c1">size_t</span> len){
<span class="pl-c">//Handle WebSocket event</span>
}
<span class="pl-k">void</span> <span class="pl-en">setup</span>(){
Serial.<span class="pl-c1">begin</span>(<span class="pl-c1">115200</span>);
WiFi.<span class="pl-c1">mode</span>(WIFI_STA);
WiFi.<span class="pl-c1">begin</span>(ssid, password);
<span class="pl-k">if</span> (WiFi.<span class="pl-c1">waitForConnectResult</span>() != WL_CONNECTED) {
Serial.<span class="pl-c1">printf</span>(<span class="pl-s"><span class="pl-pds">"</span>WiFi Failed!<span class="pl-cce">\n</span><span class="pl-pds">"</span></span>);
<span class="pl-k">return</span>;
}
<span class="pl-c">// attach Async WebSockets</span>
control_ws.<span class="pl-c1">onEvent</span>(onEvent);
server.<span class="pl-c1">addHandler</span>(&amp;control_ws);
data_ws.<span class="pl-c1">onEvent</span>(onEvent);
server.<span class="pl-c1">addHandler</span>(&amp;data_ws);
<span class="pl-c">// respond to GET requests on URL /heap</span>
server.<span class="pl-c1">on</span>(<span class="pl-s"><span class="pl-pds">"</span>/heap<span class="pl-pds">"</span></span>, HTTP_GET, [](AsyncWebServerRequest *request){
request-&gt;<span class="pl-c1">send</span>(<span class="pl-c1">200</span>, <span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-c1">String</span>(ESP.<span class="pl-c1">getFreeHeap</span>()));
});
<span class="pl-c">// upload a file to /upload</span>
server.<span class="pl-c1">on</span>(<span class="pl-s"><span class="pl-pds">"</span>/upload<span class="pl-pds">"</span></span>, HTTP_POST, [](AsyncWebServerRequest *request){
request-&gt;<span class="pl-c1">send</span>(<span class="pl-c1">200</span>);
}, handleUpload);
<span class="pl-c">// send a file when /index is requested</span>
server.<span class="pl-c1">on</span>(<span class="pl-s"><span class="pl-pds">"</span>/index<span class="pl-pds">"</span></span>, HTTP_ANY, [](AsyncWebServerRequest *request){
request-&gt;<span class="pl-c1">send</span>(SPIFFS, <span class="pl-s"><span class="pl-pds">"</span>/index.htm<span class="pl-pds">"</span></span>);
});
<span class="pl-c">// HTTP basic authentication</span>
server.<span class="pl-c1">on</span>(<span class="pl-s"><span class="pl-pds">"</span>/login<span class="pl-pds">"</span></span>, HTTP_GET, [](AsyncWebServerRequest *request){
<span class="pl-k">if</span>(!request-&gt;<span class="pl-c1">authenticate</span>(http_username, http_password))
<span class="pl-k">return</span> request-&gt;<span class="pl-c1">requestAuthentication</span>();
request-&gt;<span class="pl-c1">send</span>(<span class="pl-c1">200</span>, <span class="pl-s"><span class="pl-pds">"</span>text/plain<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>Login Success!<span class="pl-pds">"</span></span>);
});
<span class="pl-c">// attach filesystem root at URL /fs </span>
server.<span class="pl-c1">serveStatic</span>(<span class="pl-s"><span class="pl-pds">"</span>/fs<span class="pl-pds">"</span></span>, SPIFFS, <span class="pl-s"><span class="pl-pds">"</span>/<span class="pl-pds">"</span></span>);
<span class="pl-c">// Catch-All Handlers</span>
<span class="pl-c">// Any request that can not find a Handler that canHandle it</span>
<span class="pl-c">// ends in the callbacks below.</span>
server.<span class="pl-c1">onNotFound</span>(onRequest);
server.<span class="pl-c1">onFileUpload</span>(onUpload);
server.<span class="pl-c1">onRequestBody</span>(onBody);
server.<span class="pl-c1">begin</span>();
}
<span class="pl-k">void</span> <span class="pl-en">loop</span>(){}</pre></div>
<footer class="site-footer">
<span class="site-footer-owner"><a href="https://github.com/me-no-dev/ESPAsyncWebServer">ESPAsyncWebServer</a> is maintained by <a href="https://github.com/me-no-dev">me-no-dev</a>.</span>
<span class="site-footer-credits">This page was generated by <a href="https://pages.github.com">GitHub Pages</a> using the <a href="https://github.com/jasonlong/cayman-theme">Cayman theme</a> by <a href="https://twitter.com/jasonlong">Jason Long</a>.</span>
</footer>
</section>
</body>
</html>

6
params.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,124 @@
/*
The MIT License (MIT)
Copyright (c) 2015 GitHub, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
.pl-c /* comment */ {
color: #969896;
}
.pl-c1 /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */,
.pl-s .pl-v /* string variable */ {
color: #0086b3;
}
.pl-e /* entity */,
.pl-en /* entity.name */ {
color: #795da3;
}
.pl-s .pl-s1 /* string source */,
.pl-smi /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ {
color: #333;
}
.pl-ent /* entity.name.tag */ {
color: #63a35c;
}
.pl-k /* keyword, storage, storage.type */ {
color: #a71d5d;
}
.pl-pds /* punctuation.definition.string, string.regexp.character-class */,
.pl-s /* string */,
.pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
.pl-sr /* string.regexp */,
.pl-sr .pl-cce /* string.regexp constant.character.escape */,
.pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */,
.pl-sr .pl-sre /* string.regexp source.ruby.embedded */ {
color: #183691;
}
.pl-v /* variable */ {
color: #ed6a43;
}
.pl-id /* invalid.deprecated */ {
color: #b52a1d;
}
.pl-ii /* invalid.illegal */ {
background-color: #b52a1d;
color: #f8f8f8;
}
.pl-sr .pl-cce /* string.regexp constant.character.escape */ {
color: #63a35c;
font-weight: bold;
}
.pl-ml /* markup.list */ {
color: #693a17;
}
.pl-mh /* markup.heading */,
.pl-mh .pl-en /* markup.heading entity.name */,
.pl-ms /* meta.separator */ {
color: #1d3e81;
font-weight: bold;
}
.pl-mq /* markup.quote */ {
color: #008080;
}
.pl-mi /* markup.italic */ {
color: #333;
font-style: italic;
}
.pl-mb /* markup.bold */ {
color: #333;
font-weight: bold;
}
.pl-md /* markup.deleted, meta.diff.header.from-file */ {
background-color: #ffecec;
color: #bd2c00;
}
.pl-mi1 /* markup.inserted, meta.diff.header.to-file */ {
background-color: #eaffea;
color: #55a532;
}
.pl-mdr /* meta.diff.range */ {
color: #795da3;
font-weight: bold;
}
.pl-mo /* meta.output */ {
color: #1d3e81;
}

424
stylesheets/normalize.css vendored Normal file
View File

@ -0,0 +1,424 @@
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */ /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}

245
stylesheets/stylesheet.css Normal file
View File

@ -0,0 +1,245 @@
* {
box-sizing: border-box; }
body {
padding: 0;
margin: 0;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 1.5;
color: #606c71; }
a {
color: #1e6bb8;
text-decoration: none; }
a:hover {
text-decoration: underline; }
.btn {
display: inline-block;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.7);
background-color: rgba(255, 255, 255, 0.08);
border-color: rgba(255, 255, 255, 0.2);
border-style: solid;
border-width: 1px;
border-radius: 0.3rem;
transition: color 0.2s, background-color 0.2s, border-color 0.2s; }
.btn + .btn {
margin-left: 1rem; }
.btn:hover {
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
background-color: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.3); }
@media screen and (min-width: 64em) {
.btn {
padding: 0.75rem 1rem; } }
@media screen and (min-width: 42em) and (max-width: 64em) {
.btn {
padding: 0.6rem 0.9rem;
font-size: 0.9rem; } }
@media screen and (max-width: 42em) {
.btn {
display: block;
width: 100%;
padding: 0.75rem;
font-size: 0.9rem; }
.btn + .btn {
margin-top: 1rem;
margin-left: 0; } }
.page-header {
color: #fff;
text-align: center;
background-color: #159957;
background-image: linear-gradient(120deg, #155799, #159957); }
@media screen and (min-width: 64em) {
.page-header {
padding: 5rem 6rem; } }
@media screen and (min-width: 42em) and (max-width: 64em) {
.page-header {
padding: 3rem 4rem; } }
@media screen and (max-width: 42em) {
.page-header {
padding: 2rem 1rem; } }
.project-name {
margin-top: 0;
margin-bottom: 0.1rem; }
@media screen and (min-width: 64em) {
.project-name {
font-size: 3.25rem; } }
@media screen and (min-width: 42em) and (max-width: 64em) {
.project-name {
font-size: 2.25rem; } }
@media screen and (max-width: 42em) {
.project-name {
font-size: 1.75rem; } }
.project-tagline {
margin-bottom: 2rem;
font-weight: normal;
opacity: 0.7; }
@media screen and (min-width: 64em) {
.project-tagline {
font-size: 1.25rem; } }
@media screen and (min-width: 42em) and (max-width: 64em) {
.project-tagline {
font-size: 1.15rem; } }
@media screen and (max-width: 42em) {
.project-tagline {
font-size: 1rem; } }
.main-content :first-child {
margin-top: 0; }
.main-content img {
max-width: 100%; }
.main-content h1, .main-content h2, .main-content h3, .main-content h4, .main-content h5, .main-content h6 {
margin-top: 2rem;
margin-bottom: 1rem;
font-weight: normal;
color: #159957; }
.main-content p {
margin-bottom: 1em; }
.main-content code {
padding: 2px 4px;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 0.9rem;
color: #383e41;
background-color: #f3f6fa;
border-radius: 0.3rem; }
.main-content pre {
padding: 0.8rem;
margin-top: 0;
margin-bottom: 1rem;
font: 1rem Consolas, "Liberation Mono", Menlo, Courier, monospace;
color: #567482;
word-wrap: normal;
background-color: #f3f6fa;
border: solid 1px #dce6f0;
border-radius: 0.3rem; }
.main-content pre > code {
padding: 0;
margin: 0;
font-size: 0.9rem;
color: #567482;
word-break: normal;
white-space: pre;
background: transparent;
border: 0; }
.main-content .highlight {
margin-bottom: 1rem; }
.main-content .highlight pre {
margin-bottom: 0;
word-break: normal; }
.main-content .highlight pre, .main-content pre {
padding: 0.8rem;
overflow: auto;
font-size: 0.9rem;
line-height: 1.45;
border-radius: 0.3rem; }
.main-content pre code, .main-content pre tt {
display: inline;
max-width: initial;
padding: 0;
margin: 0;
overflow: initial;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0; }
.main-content pre code:before, .main-content pre code:after, .main-content pre tt:before, .main-content pre tt:after {
content: normal; }
.main-content ul, .main-content ol {
margin-top: 0; }
.main-content blockquote {
padding: 0 1rem;
margin-left: 0;
color: #819198;
border-left: 0.3rem solid #dce6f0; }
.main-content blockquote > :first-child {
margin-top: 0; }
.main-content blockquote > :last-child {
margin-bottom: 0; }
.main-content table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all; }
.main-content table th {
font-weight: bold; }
.main-content table th, .main-content table td {
padding: 0.5rem 1rem;
border: 1px solid #e9ebec; }
.main-content dl {
padding: 0; }
.main-content dl dt {
padding: 0;
margin-top: 1rem;
font-size: 1rem;
font-weight: bold; }
.main-content dl dd {
padding: 0;
margin-bottom: 1rem; }
.main-content hr {
height: 2px;
padding: 0;
margin: 1rem 0;
background-color: #eff0f1;
border: 0; }
@media screen and (min-width: 64em) {
.main-content {
max-width: 64rem;
padding: 2rem 6rem;
margin: 0 auto;
font-size: 1.1rem; } }
@media screen and (min-width: 42em) and (max-width: 64em) {
.main-content {
padding: 2rem 4rem;
font-size: 1.1rem; } }
@media screen and (max-width: 42em) {
.main-content {
padding: 2rem 1rem;
font-size: 1rem; } }
.site-footer {
padding-top: 2rem;
margin-top: 2rem;
border-top: solid 1px #eff0f1; }
.site-footer-owner {
display: block;
font-weight: bold; }
.site-footer-credits {
color: #819198; }
@media screen and (min-width: 64em) {
.site-footer {
font-size: 1rem; } }
@media screen and (min-width: 42em) and (max-width: 64em) {
.site-footer {
font-size: 1rem; } }
@media screen and (max-width: 42em) {
.site-footer {
font-size: 0.9rem; } }