15
\$\begingroup\$

Write a program that accepts HTTP requests on any port of your choice above 1024, and responds to requests on any URL of your choice with its own source code. It must work with, at least, Firefox and Chrome. The code should be delivered as text/plain (removed requirement because none of the answers but one met it) with no formatting. There is no restriction on the URL, except that it must not be used to encode any portion of the code; serving on the root is encouraged and likely the shortest solution, but is not required.

Standard quine restrictions apply. Web server frameworks are allowed, but are considered separate languages, so, for example, a Python + Flask answer does not compete with a stdlib-only Python answer.

Bonus for HTTPS support:

HTTPS HTTP Bonus
No Yes None
Yes No 10%
Yes Yes 15%
Yes Redirects to HTTPS 20%

If you do include HTTPS support, you may access the certificate by any reasonable means.

\$\endgroup\$
6
  • 2
    \$\begingroup\$ Does it need to respond to multiple requests? \$\endgroup\$
    – gsitcia
    Nov 30, 2023 at 3:12
  • \$\begingroup\$ @gsitcia no, except that to claim the 20% bonus for redirecting HTTP to HTTPS, it must be able to handle the initial HTTP request and the resulting HTTPS request. Otherwise, it's okay if it closes after one request. \$\endgroup\$
    – Someone
    Nov 30, 2023 at 3:59
  • 1
    \$\begingroup\$ Is it okay if the port is chosen randomly at startup? \$\endgroup\$
    – corvus_192
    Nov 30, 2023 at 19:44
  • \$\begingroup\$ @corvus_192 that is okay, as long as there is some indication of what port is used, such as printing it to stdout \$\endgroup\$
    – Someone
    Nov 30, 2023 at 19:47
  • 1
    \$\begingroup\$ Is it cheating to just serve the source file? \$\endgroup\$
    – noodle man
    Dec 5, 2023 at 14:00

10 Answers 10

10
\$\begingroup\$

Javascript (Node.js), 77 bytes

(f=x=>require('http').createServer((_,x)=>x.end(`(f=${f})()`)).listen(1e4))()
\$\endgroup\$
3
  • \$\begingroup\$ 76 bytes with express: (f=x=>require('express')().get('',(_,r)=>r.end((f=${f})())).listen(1e4))() \$\endgroup\$
    – corvus_192
    Nov 30, 2023 at 19:47
  • \$\begingroup\$ @corvus_192 Not vanilla and Web server frameworks are allowed, but are considered separate languages \$\endgroup\$
    – l4m2
    Dec 1, 2023 at 0:31
  • \$\begingroup\$ I know, but the code is so similar, I didn't want to post it as a separate answer. \$\endgroup\$
    – corvus_192
    Dec 1, 2023 at 11:28
7
\$\begingroup\$

Python 3, 176 bytes

_='_=%r;a=%r;exec(a)';a="from socket import*;s=socket();s.bind(('',9000));s.listen()\nwhile 1:q,c=s.accept();q.send(b'HTTP/1.0\\n\\n'+(_%(_,a)).encode());q=q.recv(999)";exec(a)

Listens to any requests to localhost:9000.

Only listening for one request saves 11 bytes

165 bytes

_='_=%r;a=%r;exec(a)';a="from socket import*;s=socket();s.bind(('',9000));s.listen();q,c=s.accept();q.send(b'HTTP/1.0\\n\\n'+(_%(_,a)).encode());q.recv(999)";exec(a)

Both browsers (Firefox 120.0 & Chromium 119.0.6045.159) seem to be happy to accept responses with no status code.

147 bytes (only Firefox)

_='_=%r;a=%r;exec(a)';a="from socket import*;s=socket();s.bind(('',9000));s.listen();q,c=s.accept();q.send((_%(_,a)).encode());q.recv(999)";exec(a)

Firefox still supports HTTP/0.9

146 bytes (only Chromium)

_='_=%r;a=%r;exec(a)';a="from socket import*;s=socket();s.bind(('',9000));s.listen();s.accept()[0].send(b'HTTP\\n\\n'+(_%(_,a)).encode())";exec(a)

Chromium doesn't seem to require the '/1.0' part, and also doesn't care if the server closes the connection early (?)

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Can you replace 9000 with 9e3 or even -1 for port 65535? \$\endgroup\$
    – ATaco
    Nov 30, 2023 at 3:57
  • \$\begingroup\$ @ATaco I just tried it, 9e3 complains about being a float, and -1 gives an OverflowError \$\endgroup\$
    – gsitcia
    Nov 30, 2023 at 4:36
  • \$\begingroup\$ Huh, I wonder why Firefox requires Content-Length? \$\endgroup\$
    – Neil
    Nov 30, 2023 at 8:31
  • 1
    \$\begingroup\$ Actually testing it locally it's intermittent... \$\endgroup\$
    – Neil
    Nov 30, 2023 at 10:51
  • 1
    \$\begingroup\$ You can remove the space after import in from socket import *. \$\endgroup\$ Nov 30, 2023 at 22:07
7
\$\begingroup\$

Python 3 + http.server, 134 95 bytes

exec(b:="import os;open('.txt','w').write('exec(b:=%r)'%b);os.system('python -m http.server')")

Uses a simple Exec quine and writes the contents of it to .txt and then launches a simple webserver in the current folder via the python -m http.server tool. Hosts on port 8000 at /.txt

Very rarely use Python, so it might be golfable...

enter image description here

\$\endgroup\$
6
  • 2
    \$\begingroup\$ I haven't tested it, but knowing Python, can't you remove the space at ) as? \$\endgroup\$ Nov 30, 2023 at 7:45
  • 1
    \$\begingroup\$ You can provide a single string for the call argument: call(['python','-m','http.server']) -> call('python -m http.server'), removing 6 bytes. \$\endgroup\$
    – SevC_10
    Nov 30, 2023 at 17:27
  • \$\begingroup\$ why the very long subprocess.call instead of os.system? \$\endgroup\$
    – user253751
    Dec 1, 2023 at 18:42
  • 1
    \$\begingroup\$ @Somebody Unfortunately has to be .txt as otherwise it tries to download the file, rather than render it. \$\endgroup\$
    – ATaco
    Dec 2, 2023 at 4:59
  • 1
    \$\begingroup\$ @ATaco I think the challenge was to return an HTTP response with the source code, so IMO downloading is valid \$\endgroup\$
    – Seggan
    Dec 3, 2023 at 3:09
6
\$\begingroup\$

Python + Flask, 151 bytes

from flask import*;a=Flask('');s="from flask import*;a=Flask('');s=%s\[email protected]('/')\ndef i():return s%%repr(s)"
@a.route('/')
def i():return s%repr(s)

Doesn't show newlines as it's text/html. Visible on localhost:5000 and/or 127.0.0.1:5000. The obvious python and flask solution.

To be executed as a flask app. For example (on windows at least), assuming the file is called flask_app.py:

> set FLASK_APP=flask_app
> flask run

enter image description here

\$\endgroup\$
4
  • \$\begingroup\$ Can't be bothered to test it, but does this work by any chance? \$\endgroup\$ Nov 30, 2023 at 4:55
  • 1
    \$\begingroup\$ Why don't you use exec to run thethe code in the string and avoid having to duplicate it? \$\endgroup\$
    – The_spider
    Nov 30, 2023 at 20:26
  • \$\begingroup\$ "Doesn't show newlines as it's text/plain." What? did you mean text/html? \$\endgroup\$
    – Oskar Skog
    Dec 1, 2023 at 9:26
  • \$\begingroup\$ @OskarSkog yes, I indeed meant text/html \$\endgroup\$
    – lyxal
    Dec 1, 2023 at 9:48
5
\$\begingroup\$

JavaScript (Deno), 60 52 bytes

function f(){Deno.serve(_=>new Response(f+"f()")}f()

Try it at the Deno Deploy Playground! (Outdated).

Saved 5 bytes by using a function declaration instead of an arrow function, because Deno runs in strict mode where you need let in variable declarations:

let f=_=>…`let f=${f};f()`…;f()
function f(){…f+"f()"…}f()
// allowed in Node, but not in Deno:
f=_=>…`f=${f};f()`…;f()

Here's an alternate version that doesn't use function stringifying, stolen slightly modified from Don Hastings's wonderful quine, for 88 bytes:

let Q="let q=Q.link()[8];Deno.serve(()=>new Response(`let Q=${q+Q+q};eval(Q)`))";eval(Q)

Try it at the Deno Deploy Playground!

\$\endgroup\$
5
\$\begingroup\$

Lua + LuaSockets, 138 bytes.

b="t=require('socket').tcp()t:bind('*',-1)t:listen()c=t:accept()c:receive()c:send(('HTTP/1.0 200\\n\\nb=%qload(b)()'):format(b))"load(b)()

Stores the main code in b and loads it, then wraps it in ('...b=%qload(b)()'):format(b) to quine it. The webserver listens for any TCP connection on port 65535 (-1) and just immediately dumps the bare-minimum HTTP response to it.

enter image description here

\$\endgroup\$
5
\$\begingroup\$

Racket #lang web-server/insta, 199 bytes

#lang web-server/insta (define-syntax-rule(S n f)(define n(f'(S n f))))(S start (λ (s) (λ r (response/xexpr (~a "#lang web-server/insta (define-syntax-rule(S n f)(define n(f'(S n f))))" (~s s))))))

Running the program (e.g. with racket golf.rkt or in DrRacket) prints something like:

Your Web application is running at http://localhost:34163/servlets/standalone.rkt.
Stop this program at any time to terminate the Web Server.

and automatically launches your default browser with the page. Stopping the program (e.g. with Ctrl-C or DrRacket's Stop button) prints:


Web Server stopped.

Depending on your definition of "standard library", web-server/insta might be part of Racket's standard library. It is included in the "main distribution" you'd download from https://download.racket-lang.org.

HTTPS Only, 241 bytes

#lang web-server (define-syntax-rule(S s)(s'(S s)))(S (λ (s) (local-require web-server/servlet-env) (serve/servlet (λ r (response/xexpr (~a "#lang web-server (define-syntax-rule(S s)(s'(S s)))" (~s s)))) #:ssl? #t #:server-root-path ".")))

This uses server-cert.pem and private-key.pem from the current directory. It serves on https://localhost:8000/servlets/standalone.rkt.

HTTP→HTTPS, 356 bytes

#lang web-server (define-syntax-rule(S s)(s'(S s)))(S (λ (s) (local-require web-server/servlet-env) (thread (λ () (serve/servlet (λ r (redirect-to "https://localhost:8443/servlets/standalone.rkt"))))) (serve/servlet (λ r (response/xexpr (~a "#lang web-server (define-syntax-rule(S s)(s'(S s)))" (~s s)))) #:port 8443 #:ssl? #t #:server-root-path ".")))

Same certificate configuration as above, but listens on http://localhost:8000/servlets/standalone.rkt and https://localhost:8443/servlets/standalone.rkt.

Original: With text/plain, 263 bytes

#lang web-server/insta (define-syntax-rule (S n f) (define n (f '(S n f)))) (S start (λ (s) (λ r (response/output #:mime-type #"text/plain;charset=utf-8" (λ (o) (fprintf o "#lang web-server/insta (define-syntax-rule (S n f) (define n (f '(S n f)))) ~s" s))))))
\$\endgroup\$
2
  • \$\begingroup\$ It's a shame we can't save a few more bytes by removing spaces in the body of start; I tried, and (I think because of the macro) the response puts them back in. \$\endgroup\$ Dec 5, 2023 at 14:47
  • \$\begingroup\$ @D.BenKnoble I tried, too: the issue is that write emits conventional whitespace, not the minimum possible whitespace. \$\endgroup\$ Dec 5, 2023 at 17:10
2
\$\begingroup\$

PowerShell Core, 149 bytes

$f={($h=[Net.HttpListener]::new()).Prefixes.Add("http://*:9090/")
$h|% s*t
(($r=$h|% G*t|% R*e)|% o*).Write([byte[]]("`$f={$f}"|% t*y))
$r.Close()}

Run it using &$f
Listens on port 9090
Replies only once and does not free the port

Example output

\$\endgroup\$
2
\$\begingroup\$

Rust, 385 bytes

use std::io::*;fn main(){write!(std::net::TcpListener::bind("127.0.0.1:8080").unwrap().accept().unwrap().0,r"HTTP/1.1 200
Content-Type:text/plain
Content-Length:385

{1}{1}{}","\x22#);}",r#"use std::io::*;fn main(){write!(std::net::TcpListener::bind("127.0.0.1:8080").unwrap().accept().unwrap().0,r"HTTP/1.1 200
Content-Type:text/plain
Content-Length:385

{1}{1}{}","\x22#);}",r#""#);}

When run as the main.rs file in a cargo project with cargo run, this program waits until you go to 127.0.0.1:8080 in your browser (this is what accept() does) and then sends over its source code and ends.

\$\endgroup\$
-1
\$\begingroup\$

Bash + ncat (from nmap), 106 bytes

h='HTTP/2\r\n\r\n';s='h=\47%s\47;s=\47%s\47;printf $h$s $h $s|ncat -lp2222';printf $h$s $h $s|ncat -lp2222
\$\endgroup\$
2
  • 1
    \$\begingroup\$ it does not return the souce code \$\endgroup\$
    – matteo_c
    Dec 2, 2023 at 17:44
  • \$\begingroup\$ It does for me in Firefox and Chrome. \$\endgroup\$
    – corvus_192
    Dec 3, 2023 at 11:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.