Status codes are broken out to a separate file for better handling, search logic moved to separate file, CSS style improvements

This commit is contained in:
Andrew Gioia 2023-12-08 15:28:41 -05:00
parent 8f3f4e65e1
commit 01d01483d0
No known key found for this signature in database
GPG Key ID: FC09694A000800C8
5 changed files with 501 additions and 251 deletions

View File

@ -1,5 +1,5 @@
<?php
class RedirectCheck
class Follow
{
// constants
const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36";
@ -141,42 +141,4 @@ class RedirectCheck
return $last['url'];
}
}
// handle form submissions
if (isset($_POST['url']))
{
// check that we got a valid URL
$url = (filter_var(trim($_POST['url']), FILTER_VALIDATE_URL))
? trim($_POST['url'])
: false;
// if so, start up the redirect checks
if ($url)
{
// make a request for this url and add to the path
$request = new RedirectCheck($url);
$code = '';
do {
// set the URL
$request->url = $url;
// make the curl request and update the path
$request->getHttpCode();
// end on an error
if ($request->error)
{
break;
}
// if we have a redirect to follow, update our working $url
$url = ($request->next) ? $request->next : false;
// update our code
$code = ($request->code) ? $request->code : false;
} while ($code != 200);
}
}
?>

291
codes.php Normal file
View File

@ -0,0 +1,291 @@
<?php
$codes = [
100 => [
'label' => 'Informational',
'start' => '1XX',
'range' => '199',
'codes' => [
100 => [
'name' => 'Continue',
'desc' => 'Continue the request or ignore the response if the request is already finished.'
],
101 => [
'name' => 'Switching Protocols',
'desc' => 'Sent in response to a client\'s <code>Upgrade</code> request header and indicates the protocol the server is switching to.'
],
102 => [
'name' => 'Processing',
'desc' => 'Server has received and is processing the request, but no response is available yet.'
],
103 => [
'name' => 'Early Hints',
'desc' => 'Intended alongside <code>Link</code> header to let the user agent preconnect or start preloading resources while the server prepares a response.'
]
]
],
200 => [
'label' => 'Successful',
'start' => '2XX',
'range' => '299',
'codes' => [
200 => [
'name' => 'OK',
'desc' => 'The request succeeded.'
],
201 => [
'name' => 'Created',
'desc' => 'The request succeeded, and a new resource was created as a result.'
],
202 => [
'name' => 'Accepted',
'desc' => 'The request has been received but not yet acted upon.'
],
203 => [
'name' => 'Non-Authoritative Information',
'desc' => 'Typically for mirrors of original resources, the returned metadata is not exactly the same as is available from the origin server but is collected from a local or a third-party copy.'
],
204 => [
'name' => 'No Content',
'desc' => 'There is no content to send for this request, but the headers may be useful.'
],
205 => [
'name' => 'Reset Content',
'desc' => 'Tells the user agent to reset the document which sent this request.'
],
206 => [
'name' => 'Partial Content',
'desc' => 'Only part of a resource is sent in response to the <code>Range</code> header.'
],
207 => [
'name' => 'Multi-Status',
'desc' => 'Conveys information about multiple resources, for situations where multiple status codes might be appropriate.'
],
208 => [
'name' => 'Already Reported (WebDAV)',
'desc' => 'Used inside a <code>&lt;dav:propstat&gt;</code> response element to limit repetition.'
],
226 => [
'name' => 'IM Used',
'desc' => 'For <code>HTTP Delta encoding</code> when the server has fullfilled a <code>GET</code> request and the response is from 1+ instance manipulations.'
]
]
],
300 => [
'label' => 'Redirection',
'start' => '3XX',
'range' => '399',
'codes' => [
300 => [
'name' => 'Multiple Choices',
'desc' => 'The request has more than one possible response and the user agent or user should choose one of them.'
],
301 => [
'name' => 'Moved Permanently',
'desc' => 'The URL of the requested resource has been changed permanently. The new URL is given in the response.'
],
302 => [
'name' => 'Found',
'desc' => 'URI of the requested resource has been changed temporarily and may change in the future.'
],
303 => [
'name' => 'See Other',
'desc' => 'Client should get the requested resource at another URI with a GET request.'
],
304 => [
'name' => 'Not Modified',
'desc' => 'For caching purposes, indicating the response has not been modified so the client can use the cached version.'
],
305 => [
'name' => '<del>Use Proxy</del>',
'desc' => 'Deprecated. Indicates the requested response must be accessed via proxy.'
],
306 => [
'name' => '(Reserved)',
'desc' => 'Unused and now reserved. Previously in the HTTP/1.1 spec.'
],
307 => [
'name' => 'Temporary Redirect',
'desc' => 'Client should get the requested resource at another URI via the same method. Similar to <code>302</code> but the request method must stay the same.'
],
308 => [
'name' => 'Permanent Redirect',
'desc' => 'Response is now permanently located at a new URI included in the <code>Location:</code> header. Similar to <code>301</code> but the request method must stay the same.'
]
]
],
400 => [
'label' => 'Client Error',
'start' => '4XX',
'range' => '499',
'codes' => [
400 => [
'name' => 'Bad Request',
'desc' => 'Server will not process the request due to an unspecified error by the client.'
],
401 => [
'name' => 'Unauthorized',
'desc' => 'More accurately, "unauthenticated."'
],
402 => [
'name' => '<var>Payment Required</var>',
'desc' => 'Reserved for future use in digital payment systems.'
],
403 => [
'name' => 'Forbidden',
'desc' => 'Client is unauthorized and does not have access rights to the resource.'
],
404 => [
'name' => 'Not Found',
'desc' => 'Server cannot find the requested resource. One of the most common response headers after <code>200</code>.'
],
405 => [
'name' => 'Method Not Allowed',
'desc' => 'Request method is known by the server but is not supported by the target resource. Common in APIs.'
],
406 => [
'name' => 'Not Acceptable',
'desc' => 'Server performs content negotiation with the client and does not find content that meets the user agent\'s criteria.'
],
407 => [
'name' => 'Proxy Authentication Required',
'desc' => 'Similar to <code>401 Unauthorized</code> but authentication is needed to be done by a proxy.'
],
408 => [
'name' => 'Request Timeout',
'desc' => 'Server shuts down an unnused connection by the client.'
],
409 => [
'name' => 'Conflict',
'desc' => 'Request conflicts with the current state of the server.'
],
410 => [
'name' => 'Gone',
'desc' => 'Requested resource has been permanently deleted from server, with no forwarding address.'
],
411 => [
'name' => 'Length Required',
'desc' => 'Server rejected the request because the <code>Content-Length</code> header field is not defined and the server requires it.'
],
412 => [
'name' => 'Precondition Failed',
'desc' => 'Client has indicated preconditions in its headers which the server does not meet.'
],
413 => [
'name' => 'Payload Too Large',
'desc' => 'Request entity is larger than limits defined by server.'
],
414 => [
'name' => 'URI Too Long',
'desc' => 'URI requested by the client is longer than the server is willing to interpret.'
],
415 => [
'name' => 'Unsupported Media Type',
'desc' => 'Media format of the requested data is not supported by the server.'
],
416 => [
'name' => 'Range Not Satisfiable',
'desc' => 'Size specified by the <code>Range</code> header field in the request cannot be fulfilled.'
],
417 => [
'name' => 'Expectation Failed',
'desc' => 'Expectation indicated by the <code>Expect</code> request header field cannot be met by the server.'
],
418 => [
'name' => 'I\'m a teapot',
'desc' => 'Server refuses the attempt to brew coffee with a teapot. Reference to Hyper Text Coffee Pot Control Protocol defined in April Fools\' jokes in 1998 and 2014!'
],
421 => [
'name' => 'Misdirected Request',
'desc' => 'Request was directed at a server that is not able to produce a response.'
],
422 => [
'name' => 'Unprocessable Content (WebDAV)',
'desc' => 'Request was well-formed but was unable to be followed due to semantic errors.'
],
423 => [
'name' => 'Locked (WebDAV)',
'desc' => 'Resource that is being accessed is locked.'
],
424 => [
'name' => 'Failed Dependency (WebDAV)',
'desc' => 'Request failed due to failure of a previous request.'
],
425 => [
'name' => '<var>Too Early</var>',
'desc' => 'Reserved for future use. Server is unwilling to risk processing a request that might be replayed.'
],
426 => [
'name' => 'Upgrade Required',
'desc' => 'Request currently refused over the current protocol but the server may provide a reponse should the client use a different protocol.'
],
428 => [
'name' => 'Precondition Required',
'desc' => 'Origin server requires the request to be conditional.'
],
429 => [
'name' => 'Too Many Requests',
'desc' => 'User agent has sent too many requests in a given amount of time (i.e., it\'s rate limited).'
],
431 => [
'name' => 'Request Header Fields Too Large',
'desc' => 'Server is unwilling to process the request because its header fields are too large.'
],
451 => [
'name' => 'Unavailable For Legal Reasons',
'desc' => 'User agent requested a resource that cannot legally be provided (e.g., web page censored by a government).'
]
]
],
500 => [
'label' => 'Server Error',
'start' => '5XX',
'range' => '599',
'codes' => [
500 => [
'name' => 'Internal Server Error',
'desc' => 'Server has encountered a situation it does not know how to handle. One of the most common response codes.'
],
501 => [
'name' => 'Not Implemented',
'desc' => 'Request method is not supported by the server and cannot be handled.'
],
502 => [
'name' => 'Bad Gateway',
'desc' => 'Server recieved an invalid response while acting as a gateway.'
],
503 => [
'name' => 'Service Unavailable',
'desc' => 'Server is not ready to handle the request, commonly due to maintenance downtime or overload.'
],
504 => [
'name' => 'Gateway Timeout',
'desc' => 'Server cannot get a response in time while acting as a gateway.'
],
505 => [
'name' => 'HTTP Version Not Supported',
'desc' => 'HTTP version used in the request is not supported by the server.'
],
506 => [
'name' => 'Variant Also Negotiates',
'desc' => 'Only in Transparent Content Negotiation contexts; server has an internal configuration error where the user agent\'s chosen variant is not available.'
],
507 => [
'name' => 'Insufficient Storage (WebDAV)',
'desc' => 'Server is unable to store the representation needed to successfully complete the request.'
],
508 => [
'name' => 'Loop Detected (WebDAV)',
'desc' => 'Server detected an infinite loop while processing the request.'
],
509 => [
'name' => 'Not Extended',
'desc' => 'Further extensions to the request are required for the server to fulfill it.'
],
510 => [
'name' => 'Network Authentication Required',
'desc' => 'Client needs to authenticate to gain network access.'
]
]
]
];
?>

184
index.php
View File

@ -1,5 +1,7 @@
<?php
include('class.php');
include('search.php');
include('codes.php');
?>
<!DOCTYPE html>
<html>
@ -16,40 +18,41 @@ include('class.php');
<a href="/"><span>Check a new URL</span></a>
</nav>
</menu>
<form method="post" action="index.php" type="application/x-www-form-urlencoded">
<input type="search" value="" placeholder="URL to check..." name="url">
<form method="post" action="/" type="application/x-www-form-urlencoded">
<input type="url" value="" placeholder="URL to check..." name="url">
<button type="submit">Check</button>
</form>
</header>
<main>
<?php
// error message display
if (isset($error))
{
}
// if we have a valid request object
if (isset($request) && count($request->path) > 0)
{
$steps = count($request->path) - 1;
$count = ($steps == 1) ? '1 redirect' : $steps.' redirects';
echo "
<article>
<h2>
Final destination
</h2>
<p>
The URL you traced had ".$count." and ended here:
</p>
<h2>Final destination</h2>
<p>The URL you traced had ".$count." and ended here:</p>
<p class=\"final\">
<a href=\"".$request->getFinalRedirect()."\" target=\"blank\">
".$request->getFinalRedirect()."
</a>
</p>
<h3>
Redirect trace
</h3>
<h3>Redirect trace</h3>
<table>
<thead>
<tr>
<th>Step</th>
<th>Request</th>
<th>Code</th>
<th>Redirect</th>
<th colspan=\"2\">Code</th>
</tr>
</thead>
<tbody>";
@ -58,11 +61,11 @@ if (isset($request) && count($request->path) > 0)
$item = $step['step'];
$url = $step['url'];
$code = $step['code'];
$next = ($step['next']) ? 'Yes' : '--';
$next = ($step['next']) ? '⥂⇄↩︎' : '✓';
echo "
<tr>
<td>".$item."</td>
<td>".$url."</td>
<td>".$url." <a href=\"".$url."\" target=\"blank\"><b>↗︎</b></a></td>
<td><code>".$code."</code></td>
<td>".$next."</td>
</tr>";
@ -105,142 +108,33 @@ else
<h3>
HTTP response status codes
</h3>
<?php
if (isset($codes) && is_array($codes) && !empty($codes))
{
foreach ($codes as $group)
{
echo "
<details>
<summary>
Informational (<code>1XX</code>&ndash;<code>199</code>)
".$group['label']." (<code>".$group['start']."</code>&ndash;<code>".$group['range']."</code>)
</summary>
<dl>
<dl>";
foreach ($group['codes'] as $code => $prop)
{
echo "
<!-- ".$code." -->
<dt>
<label for="100">
<code>100</code> Continue
</label>
<label for=\"".$code."\"><code>".$code."</code> ".$prop['name']."</label>
</dt>
<input type="checkbox" id="100">
<dd>Continue the request or ignore the response if the request is already finished.</dd>
<dt>
<label for="101">
<code>101</code> Switching Protocols
</label>
</dt>
<input type="checkbox" id="101">
<dd>Sent in response to a client's <code>Upgrade</code> request header and indicates the protocol the server is switching to.</dd>
<dt>
<label for="102">
<code>102</code> Processing
</label>
</dt>
<input type="checkbox" id="102">
<dd>Server has received and is processing the request, but no response is available yet.</dd>
<dt>
<label for="103">
<code>103</code> Early Hints
</label>
</dt>
<input type="checkbox" id="103">
<dd>Intended alongside <code>Link</code> header to let the user agent preconnect or start preloading resources while the server prepares a response.</dd>
<input type=\"checkbox\" id=\"".$code."\">
<dd>".$prop['desc']."</dd>";
}
echo "
</dl>
</details>
<details>
<summary>
Successful (<code>2XX</code>&ndash;<code>299</code>)
</summary>
<dl>
<dt>
<label for="200">
<code>200</code> OK
</label>
</dt>
<input type="checkbox" id="200">
<dd>The request succeeded.</dd>
<dt>
<label for="201">
<code>201</code> Created
</label>
</dt>
<input type="checkbox" id="201">
<dd>The request succeeded, and a new resource was created as a result.</dd>
<dt>
<label for="202">
<code>202</code> Accepted
</label>
</dt>
<input type="checkbox" id="202">
<dd>The request has been received but not yet acted upon.</dd>
<dt>
<label for="203">
<code>203</code> Non-Authoritative Information
</label>
</dt>
<input type="checkbox" id="203">
<dd>Typically for mirrors of original resources, the returned metadata is not exactly the same as is available from the origin server but is collected from a local or a third-party copy.</dd>
<dt>
<label for="204">
<code>204</code> No Content
</label>
</dt>
<input type="checkbox" id="204">
<dd>There is no content to send for this request, but the headers may be useful.</dd>
<dt>
<label for="205">
<code>205</code> Reset Content
</label>
</dt>
<input type="checkbox" id="205">
<dd>Tells the user agent to reset the document which sent this request.</dd>
<dt>
<label for="206">
<code>206</code> Partial Content
</label>
</dt>
<input type="checkbox" id="206">
<dd>Only part of a resource is sent in response to the <code>Range</code> header.</dd>
<dt>
<label for="207">
<code>207</code> Multi-Status
</label>
</dt>
<input type="checkbox" id="207">
<dd>Conveys information about multiple resources, for situations where multiple status codes might be appropriate.</dd>
<dt>
<label for="208">
<code>208</code> Already Reported (WebDAV)
</label>
</dt>
<input type="checkbox" id="208">
<dd>Used inside a <code>&lt;dav:propstat&gt;</code> response element to limit repetition.</dd>
<dt>
<label for="226">
<code>226</code> IM Used
</label>
</dt>
<input type="checkbox" id="226">
<dd>For <code>HTTP Delta encoding</code> when the server has fullfilled a <code>GET</code> request and the response is from 1+ instance manipulations.</dd>
</dl>
</details>
<details>
<summary>
Redirects (<code>3XX</code>&ndash;<code>399</code>)
</summary>
<p>
300
</p>
</details>
<details>
<summary>
Client error (<code>4XX</code>&ndash;<code>499</code>)
</summary>
<p>
100
</p>
</details>
<details>
<summary>
Server error (<code>5XX</code>&ndash;<code>599</code>)
</summary>
<p>
500
</p>
</details>
</details>";
}
}
?>
<p>
See <a href="https://httpwg.org/specs/rfc9110.html#overview.of.status.codes">RFC 9110</a> for official documentation on each status code.
</p>

46
search.php Normal file
View File

@ -0,0 +1,46 @@
<?php
// handle form submissions
if (isset($_POST['url']))
{
// check that we got a valid URL
$url = (filter_var(trim($_POST['url']), FILTER_VALIDATE_URL))
? trim($_POST['url'])
: false;
// if so, start up the redirect checks
if ($url)
{
// make a request for this url and add to the path
$request = new Follow($url);
$code = '';
do {
// set the URL
$request->url = $url;
// make the curl request and update the path
$request->getHttpCode();
// end on an error
if ($request->error)
{
break;
}
// if we have a redirect to follow, update our working $url
$url = ($request->next) ? $request->next : false;
// update our code
$code = ($request->code) ? $request->code : false;
} while ($code != 200);
}
else
{
$error = [
'type' => 'search',
'message' => 'There was an issue with URL you searched. Make sure it\'s a well-formed URL.'
];
}
}
?>

View File

@ -23,7 +23,7 @@ header {
background: #fff;
display: flex;
flex-direction: column;
padding-bottom: 3rem;
height: 14rem;
width: 100%;
}
@ -79,7 +79,7 @@ form {
position: relative;
width: 90%;
}
input[type="search"] {
input[type="url"] {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: 1.25rem 50%;
@ -93,7 +93,7 @@ input[type="search"] {
transition: box-shadow 150ms ease-in-out;
width: 100%;
}
input[type="search"]:focus {
input[type="url"]:focus {
outline: none;
box-shadow: inset 0 0.25rem 0 0 #f0eded, 0 0 0 1px #fff, 0 0 0 0.25rem #39b9e4;
}
@ -132,6 +132,8 @@ article {
}
aside {
max-height: calc(100vh - 16.5rem);
overflow: auto;
width: 86%;
}
details {
@ -151,6 +153,30 @@ details dl {
details dl dt {
margin: 0 0 0.5rem;
}
details dl dt del,
details dl dt var {
align-items: center;
display: inline-flex;
flex-direction: row;
font-style: normal;
}
details dl dt del::after,
details dl dt var::after {
background-repeat: no-repeat;
background-size: 1rem 1rem;
background-position: 100% 50%;
content: '';
display: block;
height: 1rem;
margin-left: 0.5rem;
width: 1rem;
}
details dl dt del::after {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6'/%3E%3Cpath d='M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2'/%3E%3Cline x1='10' x2='10' y1='11' y2='17'/%3E%3Cline x1='14' x2='14' y1='11' y2='17'/%3E%3C/svg%3E");
}
details dl dt var::after {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 2v7.527a2 2 0 0 1-.211.896L4.72 20.55a1 1 0 0 0 .9 1.45h12.76a1 1 0 0 0 .9-1.45l-5.069-10.127A2 2 0 0 1 14 9.527V2'/%3E%3Cpath d='M8.5 2h7'/%3E%3Cpath d='M7 16h10'/%3E%3C/svg%3E");
}
details dl dd {
display: none;
font-size: 0.875rem;
@ -158,6 +184,9 @@ details dl dd {
margin-left: 0;
padding: 0 0 1rem 0.1rem;
}
details dl dd code {
font-size: 0.8rem;
}
details dl input[type="checkbox"] {
display: none;
}
@ -174,6 +203,7 @@ code {
background: #fff;
padding: 0.1rem 0.2rem;
border-radius: 0.25rem;
white-space: nowrap;
}
h2 {
@ -222,9 +252,36 @@ td {
vertical-align: top;
word-wrap: anywhere;
}
td:nth-child(2) {
line-height: 1.5rem;
padding: 0.8rem 1rem;
}
td:nth-child(2) a:hover {
text-decoration-color: transparent;
}
td b {
border: 1px solid #aaa;
border-right-width: 2px;
border-bottom-width: 2px;
border-radius: 0.25rem;
color: #555;
font-weight: 500;
line-height: 1;
margin-left: 0.5rem;
padding: 0 0.25rem;
transition: border-color 150ms ease-in-out, color 150ms ease-in-out;
}
td:nth-child(2) a:hover b {
border-color: #1a1a1a;
color: #1a1a1a;
}
tbody tr:nth-child(odd) td {
background-color: #fff;
}
tbody td:last-child {
padding-left: 0;
width: 1rem;
}
caption {
caption-side: bottom;
line-height: 1.5rem;