418: I'm a teapot

As we all should know, there's a HTTP status code 418: I'm a teapot.

Your mission, should you choose to accept it, is to use your creativitea and write the smallest possible server that responds with the above status code to any and every HTTP request made to it.

Standard loopholes apply, including

Fetching the desired output from an external source

This includes doing an HTTP request to fetch the page with the question and extracting a solution from that page. This was mildly amusing back in 2011, but now is derivative and uninteresting.

Meaning you cannot simply redirect the request to another server to have it return the response.

Your server can do anything (or nothing) while no HTTP request is made to it as long as it replies with the correct response once a HTTP request is made.

• to each and every http request? Surely just ones to a coffee: URI?
– dave
Nov 19, 2014 at 18:24
• May we assume we already have root privileges? (e.g. bind() to port 80 is ok) Nov 19, 2014 at 20:03
• @DigitalTrauma Yes, you can assume escalated privileges for your server. Nov 19, 2014 at 23:26
• @Knerd I'm leaning on the no side, you're not writing a program, you're simply configuring one. Nov 20, 2014 at 17:10
• omg. With the IOT coming around, this status code may have an actual reason to exist! Nov 20, 2014 at 18:48

GNU Awk: 69 characters

A server itself (endlessly serves one request at a time), no library used.

Send 418 to everybody who connects (82 69 characters):

BEGIN{while(s="/inet/tcp/80/0/0"){print"HTTP/1.1 418\n"|&s
close(s)}}

Send 418 to everybody who sends something (93 80 characters):

BEGIN{while(s="/inet/tcp/80/0/0"){s|&getline
print"HTTP/1.1 418\n"|&s
close(s)}}

Send 418 to everybody who sends a valid HTTP GET request (122 109 characters):

BEGIN{while(s="/inet/tcp/80/0/0"){s|&getline
if(/^GET \S+ HTTP\/1\.[01]$/)print"HTTP/1.1 418\n"|&s close(s)}} • But .. how to connect ? ;) Nov 19, 2014 at 13:31 • The same way you connect to any web server. Browser, netcat, telnet, wget, curl, another GNU awk script, … Theoretically it listens on localhost:80, but for that 1) no web server, Skype or other program should use port 80; 2) you have to be super user to open ports below 1024. So for testing is easier to edit the port number in the script to something like 8080 (s="/inet/tcp/8080/0/0") then connect to that. pastebin.com/zauP7LMA Nov 19, 2014 at 13:43 • I see. Cool. Awk noob here :) Nov 19, 2014 at 14:10 • You could possibly save a byte by using smaller port like 8, which is unassigned. Mar 20, 2016 at 9:01 • @HannesKarppila, that's correct. But given that all other solutions which explicitly specify a port (excepting the Haskell answer's port 8888) uses port 80, I better keep it like this for comparability. Mar 21, 2016 at 8:30 Bash (33) nc -lp80 -q1<<<"HTTP/1.1 418 ";$0
• Are the two newlines necessary? Seems to work OK with only one for me. Also by my count the above is 34 bytes - I'm guessing your editor is adding an unnecessary newline or \0 to the end of your file - you can truncate this and it still works. s='echo HTTP/1.1 418|nc -lp80 -q1;$0' ; echo${#s} gives 33 for me Nov 20, 2014 at 0:56
• @DigitalTrauma: You are right - the final newline is added automatically in here strings: Why does a bash here-string add a trailing newline char? ------ But I see two possible problems: 1. The script expects that it is stored in one of the $PATH directories or that it is called with a path (recursion by$0). ----- 2. HTTP requires that lines are terminated by \r\n not only \n. Here string should be $"HTTP/1.1 418\r\n\r" (longer readable form). ------ And finally: The script could be shorter: The -q1 parameter is not necessary. Nov 20, 2014 at 9:02 • @DigitalTrauma, @pabouk: The output needs end with two newlines. So one of the newlines was unnecessary (because of the here-string), but the echo variant does not work (at least Firefox won't recognize it as a 418). However, the \rs aren't needed. The spec says it should be \r\n\r\n, but at least Firefox and Chrome will accept \n\n, so it seems to be in the spirit of golfing not to include them. The -q1 parameter was necessary on my system, because the browser will not close the connection by itself.$0 works fine if the script is made executable and called in that manner. Nov 20, 2014 at 15:28
• @marinus Interesting - I was testing with wget which seems to be fine with just one newline Nov 20, 2014 at 16:06
• @pabouk - Interesting snippet here w3.org/Protocols/HTTP/OldServers.html: "Lines should be regarded as terminated by the Line Feed, and the preceeding Carriage Return character ignored" Nov 20, 2014 at 16:09

PHP - 85 bytes

<?for($s=socket_create_listen(80);socket_write(socket_accept($s),"HTTP/1.1 418
"););

Saved with Windows-Style (CR-LF) line endings, requires php_sockets enabled.

I actually used this as my error code for the Hard Code Golf: Create a Chatroom challenge, but no one noticed.

Browser-Friendly version

<?for(socket_getsockname($s=socket_create_listen(80),$n);$t="I'm a teapot";socket_write($c=socket_accept($s),"HTTP/1.0 418$t
Content-Length: $l <title>418$t</title><h1>$t</h1>The requested resource is not suitable for brewing coffee.<hr><i>$n:80</i>"))$l=124+strlen($n);

Start the script in the CLI, and point your browser at http://localhost.

• +1 for user firendlyness / I'm a teapot :-) Feb 25, 2015 at 7:28

Node.js (LiveScript)

net module - 76

require(\net)createServer (->it.write 'HTTP/1.1 418\r\n';it.end!) .listen 80

Ruby + Rack, 19 bytes

run->e{[418,{},[]]}

Must be saved as config.ru, and run with the rackup command.

Or if you prefer "pure" Ruby:

Rack::Handler::WEBrick.run->e{[418,{},[]]}

42 bytes + -rrack flag = 48 bytes

Bash+BSD general commands, 29

Borrowing back a little bit from other answers:

nc -lp80<<<"HTTP/1.1 418
";$0 Works for me with wget. First answer to use nc, 38 for((;;)){ nc -l 80 <<<HTTP/1.1\ 418 } I'm assuming root privileges - run as follows: sudo bash ./418.sh • @ub3rst4r Correct - That is why I stated "BSD general commands", which may be considered as a "library" from the point of view of shell scripting. From the OP: "All libraries are welcome" Nov 20, 2014 at 0:37 • A response must end with a newline, see w3.org/Protocols/HTTP/Response.html Nov 20, 2014 at 6:57 • @Nit - Yes - bash "here strings" will automatically be appended with a newline Nov 20, 2014 at 16:03 • How about nc -l 80 <<<HTTP/1.1\ 418;$0 Nov 20, 2014 at 16:46
• Sorry for the confusion with the two spaces. I did not notice that you did not use the -p switch :) I tested the code with Firefox and without two newlines the status code is not recognized. Nov 20, 2014 at 20:21

Ruby (nc system command) - 35

loop{nc -l 80 <<<"HTTP/1.1 418"}

DigitalTrauma should get the credit for the idea of using nc, however Ruby can make an infinite loop with fewer characters than Bash :)

Ruby (TCPServer) - 75

require'socket'
s=TCPServer.new 80
loop{(s.accept<<'HTTP/1.1 418
').close}

That newline is intentional -- the actual newline character is one character shorter than "\n".

Ruby (WEBrick HTTPServer) - 87

require'webrick'
(s=WEBrick::HTTPServer.new).mount_proc(?/){|_,r|r.status=418}
s.start
• A response must end with a newline, see w3.org/Protocols/HTTP/Response.html Nov 20, 2014 at 6:56
• @DigitalTrauma, I was going to use that, but then realized the backslash needs to be escaped with another backslash, so it would have been the same number of characters anyway :) Nov 20, 2014 at 17:17
• @TreyThomas Oh I see - so Ruby needs an extra level of escape here Nov 20, 2014 at 17:23

Node.js, 72

Response:

HTTP/1.1 418 I'm a Teapot
Date: Thu, 01 Apr 2021 16:12:59 GMT
Connection: keep-alive
Transfer-Encoding: chunked

0

Node.js, 80 with ES5 syntax only

The response is

HTTP/1.1 418 I'm a teapot
Date: Wed, 19 Nov 2014 21:08:27 GMT
Connection: keep-alive
Transfer-Encoding: chunked

0
• I find it just awesome that node supports that error code natively ^^ Feb 25, 2015 at 7:31
• You can use arrow functions to lower your byte count.
– user100690
Apr 1, 2021 at 16:06
• @ophact, yep, updated. Apr 1, 2021 at 16:16
• @Qwertiy wow didn't expect a response so quickly on a 6-year old answer
– user100690
Apr 1, 2021 at 17:07
• ServerResponse#writeHead() returns itself, so it can be chained with ServerResponse#end(): s.writeHead(418).end(). -2 to both codes!
– FZs
May 29, 2021 at 5:36

Python 3 106

s=__import__('socket').socket(2,1)
s.bind(('',80))
s.listen(9)
while 1:s.accept()[0].send('HTTP/1.1 418\n')
• Based on hallvabo's comment in Tips for golfing in Python, from socket import*;s=socket(AF_INET,SOCK_STREAM) is shorter. Nov 19, 2014 at 19:30
• @manatwork Thanks, is there a shorter way to infinite loop? I didn't find one in the tips... Nov 19, 2014 at 19:33
• while 1:s.accept()[0].sendall(bytes('HTTP/1.1 418\n','UTF8')) – unless I missed something. (By the way, feel free to count newlines a single characters, as the language allows them. That way you loose nothing by separating the commands by newlines instead of ;.) Nov 19, 2014 at 19:39
• You can cut off 2 characters by assuming port 80 is accessible, according to the question owner's comment. One ugly thing which may break portability, but may be acceptable here: use the constants' values directly s=socket(2,1) (at least those are their values on my Linux). Nov 20, 2014 at 11:46
• The documentation says for listen()'s parameter that “the maximum value is system-dependent (usually 5)”. So instead of 10, 9 is more that enough and 1 character shorter. And instead of bytes('HTTP/1.1 418\n','UTF8') a literal b'HTTP/1.1 418\n' is enough. Or if you make the code Python 2, then the b bytesprefix is not needed anymore. And the shorter send() also seems to be enough. Nov 20, 2014 at 17:32

import Network
import System.IO
main=listenOn(PortNumber 8888)>>=f
f s=do{(h,_,_)<-accept s;hPutStr h"HTTP/1.1 418\r\n";hFlush h;hClose h;f s}

R, 80 characters

Never did socket programming with R before, but I'll give it a try:

repeat{s=socketConnection(,80,T,open="r+");cat("HTTP/1.1 418\n",file=s);close(s)}

Here socketConnection opens a socket: first argument should be the host, the default being localhost we can skip it here; the second argument is the port which has no default, then argument server when specified TRUE creates the socket, if FALSE it just connects to an existing one. T is, by default, equals to TRUE, in R.

Edit: As suggested in a suggested edit by @AlexBrown, this could be shorten into 69 characters:

repeat cat("HTTP/1.1 418\n",file=s<-socketConnection(,80,T))+close(s)
• According to the HTTP specifications, HTTP responses must end in \r\n, so you have to add two bytes. Jun 8, 2021 at 20:21

Shell + socat, 60

socat tcp-l:80,fork exec:'printf HTTP/1.1\\ 418\\ T\r\n\r\n'
• echo -e HTTP/1.1 418 T\r\n\r is shorter. Nov 20, 2014 at 15:02
• The \\ T isn't even needed. Nov 30, 2014 at 17:51

Tcl (>= 8.5), 78 bytes

Edit - added in an extra newline (total of 2 newlines) for the sake of compliance.

socket -server {apply {{c - -} {puts $c "HTTP/1.1 418 ";close$c}}} 80
vwait f
• A response must end with a newline, see w3.org/Protocols/HTTP/Response.html Nov 20, 2014 at 6:58
• @Nit - Yes, Tcl puts will automatically append a newline, unless the -nonewline option is given. tcl.tk/man/tcl/TclCmd/puts.htm Nov 20, 2014 at 16:05

Powershell, 398

$Listener = New-Object System.Net.Sockets.TcpListener([System.Net.IPAddress]::Parse("10.10.10.10"), 80)$Listener.Start()
while($true) {$RemoteClient = $Listener.AcceptTcpClient()$Stream = $RemoteClient.GetStream()$Writer = New-Object System.IO.StreamWriter $Stream$Writer.Write("HTTP/1.1 418 I'm a TeapotnConnection: Closenn")
$Writer.Flush()$RemoteClient.Close()
}

258

$l=New-Object System.Net.Sockets.TcpListener([System.Net.IPAddress]::Parse("10.10.10.10"),80);$l.Start();while($true){$r = $l.AcceptTcpClient();$s = $r.GetStream();$w = New-Object System.IO.StreamWriter $s;$w.Write("HTTP/1.1 418n`n");$w.Flush();$r.Close()}

Julia 0.6, 86 73 bytes

s=listen(80)
while 1<2
c=accept(s)
write(c,"HTTP/1.1 418

")
close(c)
end
• I don't think you need the actual "I'm a teapot" part -- the response code should be enough. Nov 21, 2014 at 10:22
• Yes, I noticed it. But as that won't help much on Julia's score I kept it complete. But probably would be better to remove it to facilitate comparison of languages. Nov 21, 2014 at 11:08
• According to the HTTP specifications, HTTP responses must end in \r\n, so this is invalid. You can fix it at no cost, however, by replacing the first LF with a CR. Jun 8, 2021 at 20:24

Node.js koa, 61 Bytes

require('koa')().use(function*(){this.status=418}).listen(80)

Response:

HTTP/1.1 418 I'm a teapot
X-Powered-By: koa
Content-Type: text/plain; charset=utf-8
Content-Length: 12
Date: Thu, 20 Nov 2014 07:20:36 GMT
Connection: close

I'm a teapot

Requires node v0.11.12 +

Run as:

node --harmony app.js
• What's function*? Nov 30, 2014 at 17:53
• That's a generator function, part of the ECMAScript 6, Harmony proposal. Dec 1, 2014 at 5:56

MATLAB, 97 86 bytes

Not really a serious contender in terms of absolute byte-count, but I'd like to post it because I didn't think it would be possible to write a fully functional webserver using a mathematical tool. Note the use of property shortening: 'Ne','s' internally expands to 'NetworkRole', 'server'.

t=tcpip('0.0.0.0','Ne','s');while 1
fopen(t)
fprintf(t,'HTTP/1.1 418\n')
fclose(t)
end
• According to the HTTP specifications, HTTP responses must end in \r\n, so you have to add two bytes. Jun 8, 2021 at 20:21
• @Makonede Instead of commenting on every single answer here you could've left a single comment on the OP if the \r\n is required. Either way, I strongly feel this is not worth digging up a seven year old challenge for... Jun 8, 2021 at 20:39

Perl, 78

use Web::Simple;sub dispatch_request{sub{[418,[],[]]}}__PACKAGE__->to_psgi_app

run as plackup whatever.pl.

• If you want a plack application, then just sub{[418,[],[]]} should be sufficient. (16 characters.) Nov 24, 2014 at 3:57
• Of course you're right! It's not like I'm using any of the framework, why load it? :) Nov 24, 2014 at 4:55
• @tobyink feel free to submit it as your own though :) Nov 24, 2014 at 4:56

Go, 162 bytes

package main
import "net/http"
http.ListenAndServe(":80", nil)
}

Python 2.7/Django, 94 bytes

import django.http.HttpResponse as r;urlpatterns=patterns(url(r'^*$',lambda q:r(status=418))) node.js with CoffeeScript (76) require("connect")().use((q,s,n)->s.writeHead 418;s.end();return;).listen 80 Just compile it to JavaScript, then you need to run npm install connect. After that start it with node server.js Factor, 101 141 bytes [ utf8 <threaded-server> readln 10 base> >>insecure [ "HTTP/1.1 418\r" print flush ] >>handler [ start-server ] in-thread start-server drop ] Return 418 to everyone who connects. C# + OWIN 251 240 I was really hoping it'd be shorter, but the long namespaces ruined that plan. Requires the Microsoft.Owin.SelfHost package available on NuGet. using Owin;class P{static void Main(){Microsoft.Owin.Hosting.WebApp.Start<P>("http://localhost");while(0<1);}public void Configuration(IAppBuilder a){a.Run(c=>{c.Response.StatusCode=418;return System.Threading.Tasks.Task.FromResult(0);});}} node.js with connect (78) require('connect')().use(function(q,s,n){s.writeHead(418);s.end()}).listen(80) You need to run npm install connect first. Then start it with node server.js You can do this with minimal effort using a .htaccess file and php. All the accesses to your server will return the status 418. Below is the code: .htaccess (28 bytes) RewriteRule .* index.php [L] PHP (38 19 bytes) <<?header(TE,1,418); Thanks to @primo for saving me a bunch of bytes! I have tested this and confirm it returns the desired result! By the way, "Pedido" means "Request" and "Resposta" means "Answer". • -1, this is not a complete program. It relies on an external web server. Nov 30, 2014 at 17:54 • @nyuszika7h Actually, it relies on Apache with PHP installed as a module. Your argument is both valid and invalid. Apache only redirects the accesses to the PHP file, the PHP file takes care of the code. Nov 30, 2014 at 17:55 • @nyuszika7h If we go down on that layer, then you can't even use the console to run your PHP code. Apache is the starter. The trigger that fires the bullet. Running the PHP file from the console, would make the console the trigger. Nov 30, 2014 at 18:01 • You're relying on having Apache already running, and I don't think it will work without changing the default configuration either. I don't care what you say, there's no way I can see this as being valid. But you should ask @Nit, as it's their question. Nov 30, 2014 at 18:02 • @nyuszika7h If it was invalid, the OP would have said already. Nov 30, 2014 at 18:05 Java 7, 208 bytes import java.net.*;class R{public static void main(String[]a)throws Exception{for(ServerSocket s=new ServerSocket(80);;){Socket p=s.accept();p.getOutputStream().write("HTTP/1.0 418\n".getBytes());p.close();}}} This question needed a java answer. poke@server ~$ curl -i localhost:80
HTTP/1.0 418
• Where is status message? Feb 28, 2017 at 20:53
• @Qwertiy I think this question only asks for status code which I interpret as the integer, so it follows that the status message/reason is not strictly required.
– Poke
Feb 28, 2017 at 20:55
• Not me to deside, but I think it should be with status text. Feb 28, 2017 at 20:58
• Get Java 8 already >_> Feb 28, 2017 at 21:12
• Here it is as a lambda for 148 bytes Jul 21, 2019 at 22:22

05AB1E + ncat, 7574696244 42 bytes

-12 thanks to ovs.

'‚«™’ÿ.¬•"n—Ä -k¯à80<<<'HTTP/1.1 418
'"’.E

Your ISP must be AT&T for this to work, as it abuses AT&T's automatic conversion of \n to \r\n in HTTP requests.

'‚«™’...’.E  # trimmed program
.E  # evaluate...
’...’    # "ÿ.shell\"ncat -klp80<<<'HTTP/1.1 418\n'\""...
# (implicit) with ÿ replaced by...
'‚«          # "system"...
™         # in title case...
.E  # as Elixir code

====================

System.shell"..."  # trimmed program
System.shell       # execute shell command...
"..."  # literal

====================

ncat -klp80<<<'...'  # trimmed program
ncat                 # host web server...
- l             # that listens to requests...
-k              # forever...
-  p            # on port...
80          # literal...
ncat                 # that returns response input...
<<<       # with...
'...'  # literal...
<<<       # as input

Side note: I do not know Elixir at all so if there are ways to improve the Elixir code please let me know.

05AB1E (legacy) + ncat, 6454 52 bytes

’__£Ø__('ï´').‚«("n—Ä -k¯à80<<<'HTTP/1.1 418\n'")’.E

’...’.E  # trimmed program
.E  # evaluate...
’...’    # "__import__('os').system(\"ncat -klp80<<<'HTTP/1.1 418\n'\")"...
.E  # as Python code

====================

__import__('os').system("...")  # trimmed program
__import__('os').system(     )  # execute shell command...
"..."   # literal

====================

ncat -klp80<<<'...'  # trimmed program
ncat                 # host web server...
- l             # that listens to requests...
-k              # forever...
-  p            # on port...
80          # literal...
ncat                 # that returns response input...
<<<       # with...
'...'  # literal...
<<<       # as input
• That's pretty cool, I didn't know 05AB1E also supported running as Elixir code, TIL. May 28, 2021 at 19:08
• @Etheryte Yeah, 05AB1E is actually written in Elixir, that's why this was added. May 28, 2021 at 19:35
• In the new version .E can evaluate single Elixir expressions, you don't need to write a full program. Did you test the current version? For me I couldn't get it to work, but this should work with the newest Elixir version.
– ovs
Jun 8, 2021 at 19:22
• @ovs Thanks for the tip about System.shell! About the comment: I am aware of that, however the nc needs to run infinitely, thus I made a recursive function. (Doesn't seem to be a better way of making an infinite loop in Elixir) Jun 8, 2021 at 19:35
• I found a way to do it without defining a module: Try it online! (Taken from this SO answer)
– ovs
Jun 8, 2021 at 19:53

nginx - 35

events{}http{server{return 418;}}

Throw that in nginx.conf, start nginx.

Not sure if this uses standard loopholes "Using built-in functions to do the work" or "Interpreting the challenge too literally." Oops, looks like OP won't like this answer.

• Would it still work if you dropped the ;? Nov 23, 2014 at 8:58
• +4/-4: well done on controversy :D
– cat
Mar 20, 2016 at 2:45

Python 3 + Flask, 648076 75 bytes

I don't know much Flask, so I'm not entirely sure if this works. Please let me know in the comments if there's some problem with this. Ungolfed version:

@app.route("/")
def index():
abort(418)

app.run("127.0.0.1", 80)

Simply binds the path "/" to a function that aborts with error code 418.

Thanks to Makonede for pointing out that I didn't start the server and giving a modification to make the solution 80 76 75 bytes. The 80 was from using app instead of a. Oops! The 76 was from (a:=Flask("")) instead of a=Flask("");a.

• You never started the server. Working 80 byte solution: from flask import*;(app:=Flask('')).route('/')(lambda:abort(418));app.run('',80) Jun 8, 2021 at 21:27
• wait i'm dumb why use app when you can use a lol. Saves 4 bytes Jun 8, 2021 at 21:59
• @Makonede Oops! I didn't catch that either, hehe. Jun 8, 2021 at 22:01
• Also -1 without :=: a=Flask('');a.route('/')(lambda:abort(418));a.run('',80) Jun 8, 2021 at 22:01
• @Makonede Oops. Right again, Makonede! Jun 8, 2021 at 22:02

Python 3 + ncat, 55 53 bytes

import os;os.system("ncat -klp80<<<'HTTP/1.1 418\n'")

Your ISP must be AT&T for this to work.

import os;os.system("...")  # trimmed program
import                      # import module named...
os                   # variable
os.system(     )  # run shell command...
"..."   # literal

====================

ncat -klp80<<<'...'  # trimmed program
ncat                 # host web server...
- l             # that listens to requests...
-k              # forever...
-  p            # on port...
80          # literal...
ncat                 # that returns response input...
<<<       # with...
'...'  # literal...
<<<       # as input