Initial commit, partially done
This commit is contained in:
commit
67e03a481f
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
.idea/
|
||||
Cargo.lock
|
||||
target/
|
||||
upload/
|
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "pastebin"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.3.14"
|
||||
rocket_codegen = "0.3.14"
|
||||
rand = "0.4"
|
||||
multipart = "0.15.2"
|
||||
toml = "0.4.6"
|
||||
adjective_adjective_animal = "0.1.0"
|
||||
#tokio = "0.1.7"
|
||||
#tokio-codec = "0.1.0"
|
23
readme.md
Normal file
23
readme.md
Normal file
@ -0,0 +1,23 @@
|
||||
Rust Bucket
|
||||
-----------
|
||||
|
||||
My ideal vision of a pastebin/image/file host, easy to use from the command line with any tools, and from a browser with and without javascript
|
||||
|
||||
Borrows ideas and inspiration from many different pastebins over the years:
|
||||
|
||||
* [ZeroBin](https://github.com/sebsauvage/ZeroBin) (client-side encryption)
|
||||
* [chefi](https://github.com/colemickens/chefi) (paste with netcat)
|
||||
* [Rocket.rs example pastebin](https://github.com/SergioBenitez/Rocket/tree/master/examples/pastebin/src) (framework)
|
||||
* [dank-paste](https://github.com/wpbirney/dank-paste) (multipart/form-data support)
|
||||
* [ix.io](http://ix.io/) (downloadable client)
|
||||
|
||||
Delete after 1/2 views, 5/10 minutes, 1 hour/day/week/month/year, forever, delete after not viewed within X
|
||||
|
||||
Don't store file type, only used for link, can use any suffix for link
|
||||
|
||||
Store when to delete (how many views + how long), store how many times viewed, store when uploaded (or file creation date?)
|
||||
|
||||
Maybe if we only support 'burn after reading' like zerobin we can use a special created_date to signify this and then never count views, or, another file, since that would interfere with 'delete after X time'
|
||||
|
||||
Crazy random thoughts:
|
||||
* hash IDs, use un-hashed ID to encrypt paste
|
328
src/main.rs
Normal file
328
src/main.rs
Normal file
@ -0,0 +1,328 @@
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
extern crate adjective_adjective_animal;
|
||||
//extern crate tokio;
|
||||
//extern crate tokio_codec;
|
||||
extern crate multipart;
|
||||
|
||||
mod paste_id;
|
||||
mod mpu;
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
use std::io;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rocket::response::NamedFile;
|
||||
|
||||
use rocket::Data;
|
||||
use rocket::response::content;
|
||||
|
||||
use paste_id::PasteID;
|
||||
use mpu::MultipartUpload;
|
||||
use rocket::request::LenientForm;
|
||||
use std::fs;
|
||||
|
||||
//use tokio_codec::{Decoder, BytesCodec};
|
||||
//use tokio::net::TcpListener;
|
||||
//use tokio::prelude::*;
|
||||
use std::thread;
|
||||
use std::net::TcpListener;
|
||||
use std::io::{Write,Read};
|
||||
use std::time::Duration;
|
||||
|
||||
const HOST: &'static str = "http://localhost:8000";
|
||||
|
||||
const UPLOAD_MAX_SIZE: u64 = 8 * 1024 * 1024;
|
||||
|
||||
fn new_paste() -> (String, String) {
|
||||
let id = PasteID::new();
|
||||
let filename = format!("upload/{id}", id = id);
|
||||
let url = format!("{host}/{id}\n", host = HOST, id = id);
|
||||
(filename, url)
|
||||
}
|
||||
|
||||
fn upload(paste: Data, key: Option<PasteID>) -> io::Result<String> {
|
||||
let (filename, url) = new_paste();
|
||||
|
||||
paste.stream_to_file(Path::new(&filename))?;
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
fn upload_string(paste: &str, key: Option<PasteID>) -> io::Result<String> {
|
||||
let (filename, url) = new_paste();
|
||||
|
||||
fs::write(filename, paste).expect("Unable to write file");
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
#[derive(FromForm)]
|
||||
struct PasteForm {
|
||||
content: String,
|
||||
extension: String,
|
||||
}
|
||||
|
||||
// todo: change /w to /, shouldn't conflict because of format, but it does currently
|
||||
#[post("/w", format = "application/x-www-form-urlencoded", data = "<paste>")]
|
||||
fn web_post(paste: LenientForm<PasteForm>) -> io::Result<String> {
|
||||
upload_string(&paste.get().content, None)
|
||||
}
|
||||
|
||||
// todo: change /w to /, shouldn't conflict because of format, but it does currently
|
||||
#[post("/m", format = "multipart/form-data", data = "<paste>")]
|
||||
fn mpu_post(paste: MultipartUpload) -> io::Result<String> {
|
||||
let (filename, url) = new_paste();
|
||||
|
||||
paste.stream_to_file(Path::new(&filename))?;
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
#[put("/", data = "<paste>")]
|
||||
fn upload_put(paste: Data) -> io::Result<String> {
|
||||
upload(paste, None)
|
||||
}
|
||||
|
||||
#[post("/", data = "<paste>")]
|
||||
fn upload_post(paste: Data) -> io::Result<String> {
|
||||
upload(paste, None)
|
||||
}
|
||||
|
||||
#[patch("/", data = "<paste>")]
|
||||
fn upload_patch(paste: Data) -> io::Result<String> {
|
||||
upload(paste, None)
|
||||
}
|
||||
|
||||
#[put("/<key>", data = "<paste>")]
|
||||
fn upload_put_key(paste: Data, key: PasteID) -> io::Result<String> {
|
||||
upload(paste, Some(key))
|
||||
}
|
||||
|
||||
#[post("/<key>", data = "<paste>")]
|
||||
fn upload_post_key(paste: Data, key: PasteID) -> io::Result<String> {
|
||||
upload(paste, Some(key))
|
||||
}
|
||||
|
||||
#[patch("/<key>", data = "<paste>")]
|
||||
fn upload_patch_key(paste: Data, key: PasteID) -> io::Result<String> {
|
||||
upload(paste, Some(key))
|
||||
}
|
||||
|
||||
#[get("/<id>")]
|
||||
fn get(id: PasteID) -> Option<content::Plain<File>> {
|
||||
let filename = format!("upload/{id}", id = id);
|
||||
File::open(&filename).map(|f| content::Plain(f)).ok()
|
||||
}
|
||||
|
||||
#[delete("/<id>/<key>")]
|
||||
fn delete(id: PasteID, key: PasteID) -> Option<content::Plain<File>> {
|
||||
let filename = format!("upload/{id}", id = id);
|
||||
File::open(&filename).map(|f| content::Plain(f)).ok()
|
||||
}
|
||||
|
||||
#[patch("/<id>/<key>")]
|
||||
fn patch(id: PasteID, key: PasteID) -> Option<content::Plain<File>> {
|
||||
let filename = format!("upload/{id}", id = id);
|
||||
File::open(&filename).map(|f| content::Plain(f)).ok()
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> io::Result<NamedFile> {
|
||||
NamedFile::open("static/index.html")
|
||||
}
|
||||
|
||||
#[get("/static/<file..>")]
|
||||
fn files(file: PathBuf) -> Option<NamedFile> {
|
||||
NamedFile::open(Path::new("static/").join(file)).ok()
|
||||
}
|
||||
|
||||
fn rocket() -> rocket::Rocket {
|
||||
rocket::ignite().mount("/", routes![
|
||||
index, files,
|
||||
web_post,
|
||||
mpu_post,
|
||||
upload_post, upload_put, upload_patch,
|
||||
upload_post_key, upload_put_key, upload_patch_key,
|
||||
get, delete, patch
|
||||
])
|
||||
}
|
||||
|
||||
// adapted from io::copy
|
||||
fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
|
||||
where R: Read, W: Write
|
||||
{
|
||||
let mut buf : [u8; 8192] = [0; 8192];
|
||||
|
||||
let mut written = 0;
|
||||
loop {
|
||||
let len = match reader.read(&mut buf) {
|
||||
Ok(0) => return Ok(written),
|
||||
Ok(len) => len,
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
writer.write_all(&buf[..len])?;
|
||||
written += len as u64;
|
||||
if written > UPLOAD_MAX_SIZE {
|
||||
return Err(std::io::Error::from(std::io::ErrorKind::InvalidData))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_tcp(){
|
||||
// Bind the server's socket
|
||||
thread::spawn(|| {
|
||||
let timeout = Some(Duration::new(5, 0));
|
||||
let mut listener = TcpListener::bind("127.0.0.1:12345").unwrap();
|
||||
|
||||
loop {
|
||||
match listener.accept() {
|
||||
Ok((mut stream, addr)) => {
|
||||
thread::spawn(move || {
|
||||
let (filename, url) = new_paste();
|
||||
|
||||
let mut paste_file = File::create(&filename).expect("cannot create file?");
|
||||
|
||||
stream.set_read_timeout(timeout).expect("set read timeout failed?");
|
||||
stream.set_write_timeout(timeout).expect("set write timeout failed?");
|
||||
|
||||
stream.write(&url.into_bytes()).expect("write failed?");
|
||||
stream.flush();
|
||||
|
||||
copy(&mut stream, &mut paste_file);
|
||||
|
||||
//handle_request(stream, addr);
|
||||
})
|
||||
},
|
||||
Err(e) => {
|
||||
thread::spawn(move || {
|
||||
println!("Connection failed: {:?}", e)
|
||||
})
|
||||
},
|
||||
};
|
||||
};
|
||||
});
|
||||
/*
|
||||
// Bind the server's socket
|
||||
let addr = "127.0.0.1:12345".parse().unwrap();
|
||||
let tcp = TcpListener::bind(&addr).unwrap();
|
||||
|
||||
// Iterate incoming connections
|
||||
let server = tcp.incoming().for_each(|tcp| {
|
||||
|
||||
let id = PasteID::new(ID_LENGTH);
|
||||
let filename = format!("upload/{id}", id = id);
|
||||
let url = format!("{host}/{id}\n", host = HOST, id = id);
|
||||
|
||||
// Split up the read and write halves
|
||||
//let (reader, writer) = tcp.split();
|
||||
|
||||
|
||||
// Copy the data back to the client
|
||||
let conn = tokio::io::copy(reader, writer)
|
||||
// print what happened
|
||||
.map(|(n, _, _)| {
|
||||
println!("wrote {} bytes", n)
|
||||
})
|
||||
// Handle any errors
|
||||
.map_err(|err| {
|
||||
println!("IO error {:?}", err)
|
||||
});
|
||||
|
||||
let conn = tokio::io::write_all(writer, url)
|
||||
.then(|res| {
|
||||
println!("wrote message; success={:?}", res.is_ok());
|
||||
Ok(())
|
||||
});
|
||||
|
||||
|
||||
let mut paste_file = File::create(&filename)?;
|
||||
|
||||
let conn = tokio::io::re(reader, vec!(0; 4096)).then(move |res| {
|
||||
let result = match res {
|
||||
Ok((_, buf, n)) => {
|
||||
//info!(client_logger, "persisted"; "filepath" => filepath);
|
||||
paste_file.write(&buf[0..n]).unwrap();
|
||||
|
||||
//info!(client_logger, "replied"; "message" => url);
|
||||
tokio::io::write_all(writer, format!("{}\n", url).as_bytes()).wait().unwrap();
|
||||
|
||||
//info!(client_logger, "finished connection");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
//error!(client_logger, "failed to read from client");
|
||||
Err(e)
|
||||
}
|
||||
};
|
||||
drop(result);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let mut paste_file = tokio::fs::file::File::create(&filename);
|
||||
|
||||
let conn = tokio::io::copy(reader, paste_file)
|
||||
// print what happened
|
||||
.map(|(n, _, _)| {
|
||||
println!("wrote {} bytes", n)
|
||||
})
|
||||
// Handle any errors
|
||||
.map_err(|err| {
|
||||
println!("IO error {:?}", err)
|
||||
});
|
||||
|
||||
|
||||
|
||||
let framed = BytesCodec::new().framed(tcp);
|
||||
let (writer, reader) = framed.split();
|
||||
|
||||
let mut paste_file = File::create(&filename)?;
|
||||
|
||||
let conn = writer.write_buf(url)
|
||||
.then(|res| {
|
||||
println!("wrote message; success={:?}", res.is_ok());
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let conn = reader
|
||||
.for_each(move|bytes| {
|
||||
println!("bytes: {:?}", bytes);
|
||||
paste_file.write_all(&bytes).expect("cannot write to file?");
|
||||
Ok(())
|
||||
})
|
||||
// After our copy operation is complete we just print out some helpful
|
||||
// information.
|
||||
.and_then(|()| {
|
||||
println!("Socket received FIN packet and closed connection");
|
||||
Ok(())
|
||||
})
|
||||
.or_else(|err| {
|
||||
println!("Socket closed with error: {:?}", err);
|
||||
// We have to return the error to catch it in the next ``.then` call
|
||||
Err(err)
|
||||
})
|
||||
.then(|result| {
|
||||
println!("Socket closed with result: {:?}", result);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
// Spawn the future as a concurrent task
|
||||
tokio::spawn(conn);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.map_err(|err| {
|
||||
println!("server error {:?}", err);
|
||||
});
|
||||
|
||||
// Start the runtime and spin up the server
|
||||
tokio::run(server);
|
||||
*/
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
run_tcp();
|
||||
rocket().launch();
|
||||
}
|
63
src/mpu.rs
Normal file
63
src/mpu.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use std::io::prelude::*;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::io;
|
||||
|
||||
use std::io::{Read, Cursor};
|
||||
use rocket::data::{self, FromData};
|
||||
use rocket::Data;
|
||||
use rocket::Outcome;
|
||||
use rocket::request::Request;
|
||||
use rocket::http::Status;
|
||||
use multipart::server::Multipart;
|
||||
|
||||
pub struct MultipartUpload {
|
||||
file: Vec<u8>,
|
||||
}
|
||||
|
||||
impl MultipartUpload {
|
||||
pub fn stream_to_file(&self, path: &Path) -> io::Result<()> {
|
||||
let mut f = File::create(path)?;
|
||||
f.write_all(&self.file)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_multipart(request: &Request, data: Data) -> Option<Multipart<Cursor<Vec<u8>>>> {
|
||||
// All of these errors should be reported
|
||||
let ct = request.headers().get_one("Content-Type")?;
|
||||
let idx = ct.find("boundary=")?;
|
||||
let boundary = &ct[(idx + "boundary=".len())..];
|
||||
|
||||
let mut d = Vec::new();
|
||||
data.stream_to(&mut d).ok()?;
|
||||
|
||||
Some(Multipart::with_body(Cursor::new(d), boundary))
|
||||
}
|
||||
|
||||
impl FromData for MultipartUpload {
|
||||
type Error = ();
|
||||
|
||||
fn from_data(request: &Request, data: Data) -> data::Outcome<Self, Self::Error> {
|
||||
let mut mp = match get_multipart(&request, data) {
|
||||
Some(m) => m,
|
||||
None => return Outcome::Failure((Status::raw(421), ())),
|
||||
};
|
||||
|
||||
// Custom implementation parts
|
||||
let mut file = None;
|
||||
|
||||
mp.foreach_entry(|mut entry| match entry.headers.name.as_str() {
|
||||
"file" => {
|
||||
panic!("filename: {:?}", entry.headers.filename);
|
||||
let mut d = Vec::new();
|
||||
entry.data.read_to_end(&mut d).expect("cant read");
|
||||
file = Some(d);
|
||||
}
|
||||
other => panic!("No known key {}", other),
|
||||
}).expect("Unable to iterate");
|
||||
|
||||
Outcome::Success(MultipartUpload {
|
||||
file: file.expect("file not set"),
|
||||
})
|
||||
}
|
||||
}
|
51
src/paste_id.rs
Normal file
51
src/paste_id.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use std::fmt;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rocket::request::FromParam;
|
||||
use rocket::http::RawStr;
|
||||
|
||||
use adjective_adjective_animal::Generator;
|
||||
|
||||
/// A _probably_ unique paste ID.
|
||||
pub struct PasteID<'a>(Cow<'a, str>);
|
||||
|
||||
impl<'a> PasteID<'a> {
|
||||
/// Generate a _probably_ unique ID with `size` characters. For readability,
|
||||
/// the characters used are from the sets [0-9], [A-Z], [a-z]. The
|
||||
/// probability of a collision depends on the value of `size` and the number
|
||||
/// of IDs generated thus far.
|
||||
pub fn new() -> PasteID<'static> {
|
||||
let mut generator = Generator::default();
|
||||
|
||||
PasteID(Cow::Owned(generator.next().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for PasteID<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `id` is a valid paste ID and `false` otherwise.
|
||||
fn valid_id(id: &str) -> bool {
|
||||
id.len() > 3 &&
|
||||
id.chars().all(|c| {
|
||||
(c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an instance of `PasteID` if the path segment is a valid ID.
|
||||
/// Otherwise returns the invalid ID as the `Err` value.
|
||||
impl<'a> FromParam<'a> for PasteID<'a> {
|
||||
type Error = &'a RawStr;
|
||||
|
||||
fn from_param(param: &'a RawStr) -> Result<PasteID<'a>, &'a RawStr> {
|
||||
match valid_id(param) {
|
||||
true => Ok(PasteID(Cow::Borrowed(param))),
|
||||
false => Err(param)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
70
src/tests.rs
Normal file
70
src/tests.rs
Normal file
@ -0,0 +1,70 @@
|
||||
use super::{rocket, index};
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
fn extract_id(from: &str) -> Option<String> {
|
||||
from.rfind('/').map(|i| &from[(i + 1)..]).map(|s| s.trim_right().to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_index() {
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Ensure the index returns what we expect.
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::Plain));
|
||||
//assert_eq!(response.body_string(), Some(index().into()))
|
||||
}
|
||||
|
||||
fn upload_paste(client: &Client, body: &str) -> String {
|
||||
let mut response = client.post("/").body(body).dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::Plain));
|
||||
extract_id(&response.body_string().unwrap()).unwrap()
|
||||
}
|
||||
|
||||
fn download_paste(client: &Client, id: &str) -> String {
|
||||
let mut response = client.get(format!("/{}", id)).dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
response.body_string().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pasting() {
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Do a trivial upload, just to make sure it works.
|
||||
let body_1 = "Hello, world!";
|
||||
let id_1 = upload_paste(&client, body_1);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
|
||||
// Make sure we can keep getting that paste.
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
|
||||
// Upload some unicode.
|
||||
let body_2 = "こんにちは";
|
||||
let id_2 = upload_paste(&client, body_2);
|
||||
assert_eq!(download_paste(&client, &id_2), body_2);
|
||||
|
||||
// Make sure we can get both pastes.
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_2), body_2);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_2), body_2);
|
||||
|
||||
// Now a longer upload.
|
||||
let body_3 = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
|
||||
do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
||||
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
|
||||
in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
|
||||
officia deserunt mollit anim id est laborum.";
|
||||
let id_3 = upload_paste(&client, body_3);
|
||||
assert_eq!(download_paste(&client, &id_3), body_3);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_2), body_2);
|
||||
}
|
12
static/api.txt
Normal file
12
static/api.txt
Normal file
@ -0,0 +1,12 @@
|
||||
USAGE
|
||||
|
||||
POST /
|
||||
|
||||
accepts raw data in the body of the request and responds with a URL of
|
||||
a page containing the body's content
|
||||
|
||||
EXMAPLE: curl --data-binary @file.txt http://localhost:8000
|
||||
|
||||
GET /<id>
|
||||
|
||||
retrieves the content for the paste with id `<id>`
|
875
static/index.html
Normal file
875
static/index.html
Normal file
@ -0,0 +1,875 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Rust Bucket</title>
|
||||
<style type="text/css" media="screen">
|
||||
html, body, .container, form { padding: 0; height: 100%; }
|
||||
.container { margin: 10px; }
|
||||
|
||||
.error {
|
||||
border: 2px solid red;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 75%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
margin-top: 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<form action="/m"
|
||||
enctype="multipart/form-data" method="post">
|
||||
<p>
|
||||
Select a file:<br>
|
||||
<input type="file" name="file" size="40">
|
||||
</p>
|
||||
<div>
|
||||
<input type="submit" value="Send">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<form method="post" action="/w">
|
||||
<textarea name="content" rows="30" maxlength="393216" \
|
||||
placeholder="Paste your code here..." cols="80"></textarea>
|
||||
<br />
|
||||
<!--
|
||||
-->
|
||||
<label for="extension">File Extension:</label>
|
||||
<select name="extension">
|
||||
|
||||
<option value="Appfile">
|
||||
Appfile
|
||||
</option>
|
||||
|
||||
<option value="Berksfile">
|
||||
Berksfile
|
||||
</option>
|
||||
|
||||
<option value="Brewfile">
|
||||
Brewfile
|
||||
</option>
|
||||
|
||||
<option value="C">
|
||||
C
|
||||
</option>
|
||||
|
||||
<option value="Cheffile">
|
||||
Cheffile
|
||||
</option>
|
||||
|
||||
<option value="DOT">
|
||||
DOT
|
||||
</option>
|
||||
|
||||
<option value="Deliverfile">
|
||||
Deliverfile
|
||||
</option>
|
||||
|
||||
<option value="Emakefile">
|
||||
Emakefile
|
||||
</option>
|
||||
|
||||
<option value="Fastfile">
|
||||
Fastfile
|
||||
</option>
|
||||
|
||||
<option value="GNUmakefile">
|
||||
GNUmakefile
|
||||
</option>
|
||||
|
||||
<option value="Gemfile">
|
||||
Gemfile
|
||||
</option>
|
||||
|
||||
<option value="Guardfile">
|
||||
Guardfile
|
||||
</option>
|
||||
|
||||
<option value="M">
|
||||
M
|
||||
</option>
|
||||
|
||||
<option value="Makefile">
|
||||
Makefile
|
||||
</option>
|
||||
|
||||
<option value="OCamlMakefile">
|
||||
OCamlMakefile
|
||||
</option>
|
||||
|
||||
<option value="PL">
|
||||
PL
|
||||
</option>
|
||||
|
||||
<option value="R">
|
||||
R
|
||||
</option>
|
||||
|
||||
<option value="Rakefile">
|
||||
Rakefile
|
||||
</option>
|
||||
|
||||
<option value="Rantfile">
|
||||
Rantfile
|
||||
</option>
|
||||
|
||||
<option value="Rprofile">
|
||||
Rprofile
|
||||
</option>
|
||||
|
||||
<option value="S">
|
||||
S
|
||||
</option>
|
||||
|
||||
<option value="SConscript">
|
||||
SConscript
|
||||
</option>
|
||||
|
||||
<option value="SConstruct">
|
||||
SConstruct
|
||||
</option>
|
||||
|
||||
<option value="Scanfile">
|
||||
Scanfile
|
||||
</option>
|
||||
|
||||
<option value="Sconstruct">
|
||||
Sconstruct
|
||||
</option>
|
||||
|
||||
<option value="Snakefile">
|
||||
Snakefile
|
||||
</option>
|
||||
|
||||
<option value="Snapfile">
|
||||
Snapfile
|
||||
</option>
|
||||
|
||||
<option value="Thorfile">
|
||||
Thorfile
|
||||
</option>
|
||||
|
||||
<option value="Vagrantfile">
|
||||
Vagrantfile
|
||||
</option>
|
||||
|
||||
<option value="adp">
|
||||
adp
|
||||
</option>
|
||||
|
||||
<option value="applescript">
|
||||
applescript
|
||||
</option>
|
||||
|
||||
<option value="as">
|
||||
as
|
||||
</option>
|
||||
|
||||
<option value="asa">
|
||||
asa
|
||||
</option>
|
||||
|
||||
<option value="asp">
|
||||
asp
|
||||
</option>
|
||||
|
||||
<option value="babel">
|
||||
babel
|
||||
</option>
|
||||
|
||||
<option value="bash">
|
||||
bash
|
||||
</option>
|
||||
|
||||
<option value="bat">
|
||||
bat
|
||||
</option>
|
||||
|
||||
<option value="bib">
|
||||
bib
|
||||
</option>
|
||||
|
||||
<option value="bsh">
|
||||
bsh
|
||||
</option>
|
||||
|
||||
<option value="build">
|
||||
build
|
||||
</option>
|
||||
|
||||
<option value="builder">
|
||||
builder
|
||||
</option>
|
||||
|
||||
<option value="c">
|
||||
c
|
||||
</option>
|
||||
|
||||
<option value="c++">
|
||||
c++
|
||||
</option>
|
||||
|
||||
<option value="capfile">
|
||||
capfile
|
||||
</option>
|
||||
|
||||
<option value="cc">
|
||||
cc
|
||||
</option>
|
||||
|
||||
<option value="cgi">
|
||||
cgi
|
||||
</option>
|
||||
|
||||
<option value="cl">
|
||||
cl
|
||||
</option>
|
||||
|
||||
<option value="clj">
|
||||
clj
|
||||
</option>
|
||||
|
||||
<option value="cls">
|
||||
cls
|
||||
</option>
|
||||
|
||||
<option value="cmd">
|
||||
cmd
|
||||
</option>
|
||||
|
||||
<option value="config.ru">
|
||||
config.ru
|
||||
</option>
|
||||
|
||||
<option value="cp">
|
||||
cp
|
||||
</option>
|
||||
|
||||
<option value="cpp">
|
||||
cpp
|
||||
</option>
|
||||
|
||||
<option value="cpy">
|
||||
cpy
|
||||
</option>
|
||||
|
||||
<option value="cs">
|
||||
cs
|
||||
</option>
|
||||
|
||||
<option value="css">
|
||||
css
|
||||
</option>
|
||||
|
||||
<option value="css.erb">
|
||||
css.erb
|
||||
</option>
|
||||
|
||||
<option value="css.liquid">
|
||||
css.liquid
|
||||
</option>
|
||||
|
||||
<option value="csx">
|
||||
csx
|
||||
</option>
|
||||
|
||||
<option value="cxx">
|
||||
cxx
|
||||
</option>
|
||||
|
||||
<option value="d">
|
||||
d
|
||||
</option>
|
||||
|
||||
<option value="ddl">
|
||||
ddl
|
||||
</option>
|
||||
|
||||
<option value="di">
|
||||
di
|
||||
</option>
|
||||
|
||||
<option value="diff">
|
||||
diff
|
||||
</option>
|
||||
|
||||
<option value="dml">
|
||||
dml
|
||||
</option>
|
||||
|
||||
<option value="dot">
|
||||
dot
|
||||
</option>
|
||||
|
||||
<option value="dpr">
|
||||
dpr
|
||||
</option>
|
||||
|
||||
<option value="dtml">
|
||||
dtml
|
||||
</option>
|
||||
|
||||
<option value="el">
|
||||
el
|
||||
</option>
|
||||
|
||||
<option value="emakefile">
|
||||
emakefile
|
||||
</option>
|
||||
|
||||
<option value="erb">
|
||||
erb
|
||||
</option>
|
||||
|
||||
<option value="erbsql">
|
||||
erbsql
|
||||
</option>
|
||||
|
||||
<option value="erl">
|
||||
erl
|
||||
</option>
|
||||
|
||||
<option value="es6">
|
||||
es6
|
||||
</option>
|
||||
|
||||
<option value="fasl">
|
||||
fasl
|
||||
</option>
|
||||
|
||||
<option value="fcgi">
|
||||
fcgi
|
||||
</option>
|
||||
|
||||
<option value="gemspec">
|
||||
gemspec
|
||||
</option>
|
||||
|
||||
<option value="go">
|
||||
go
|
||||
</option>
|
||||
|
||||
<option value="gradle">
|
||||
gradle
|
||||
</option>
|
||||
|
||||
<option value="groovy">
|
||||
groovy
|
||||
</option>
|
||||
|
||||
<option value="gvy">
|
||||
gvy
|
||||
</option>
|
||||
|
||||
<option value="gyp">
|
||||
gyp
|
||||
</option>
|
||||
|
||||
<option value="gypi">
|
||||
gypi
|
||||
</option>
|
||||
|
||||
<option value="h">
|
||||
h
|
||||
</option>
|
||||
|
||||
<option value="h">
|
||||
h
|
||||
</option>
|
||||
|
||||
<option value="h">
|
||||
h
|
||||
</option>
|
||||
|
||||
<option value="h">
|
||||
h
|
||||
</option>
|
||||
|
||||
<option value="h++">
|
||||
h++
|
||||
</option>
|
||||
|
||||
<option value="haml">
|
||||
haml
|
||||
</option>
|
||||
|
||||
<option value="hh">
|
||||
hh
|
||||
</option>
|
||||
|
||||
<option value="hpp">
|
||||
hpp
|
||||
</option>
|
||||
|
||||
<option value="hrl">
|
||||
hrl
|
||||
</option>
|
||||
|
||||
<option value="hs">
|
||||
hs
|
||||
</option>
|
||||
|
||||
<option value="htm">
|
||||
htm
|
||||
</option>
|
||||
|
||||
<option value="html">
|
||||
html
|
||||
</option>
|
||||
|
||||
<option value="html.erb">
|
||||
html.erb
|
||||
</option>
|
||||
|
||||
<option value="hxx">
|
||||
hxx
|
||||
</option>
|
||||
|
||||
<option value="inc">
|
||||
inc
|
||||
</option>
|
||||
|
||||
<option value="inl">
|
||||
inl
|
||||
</option>
|
||||
|
||||
<option value="ipp">
|
||||
ipp
|
||||
</option>
|
||||
|
||||
<option value="irbrc">
|
||||
irbrc
|
||||
</option>
|
||||
|
||||
<option value="java">
|
||||
java
|
||||
</option>
|
||||
|
||||
<option value="jbuilder">
|
||||
jbuilder
|
||||
</option>
|
||||
|
||||
<option value="js">
|
||||
js
|
||||
</option>
|
||||
|
||||
<option value="js.erb">
|
||||
js.erb
|
||||
</option>
|
||||
|
||||
<option value="json">
|
||||
json
|
||||
</option>
|
||||
|
||||
<option value="jsp">
|
||||
jsp
|
||||
</option>
|
||||
|
||||
<option value="jsx">
|
||||
jsx
|
||||
</option>
|
||||
|
||||
<option value="l">
|
||||
l
|
||||
</option>
|
||||
|
||||
<option value="lhs">
|
||||
lhs
|
||||
</option>
|
||||
|
||||
<option value="lisp">
|
||||
lisp
|
||||
</option>
|
||||
|
||||
<option value="lsp">
|
||||
lsp
|
||||
</option>
|
||||
|
||||
<option value="ltx">
|
||||
ltx
|
||||
</option>
|
||||
|
||||
<option value="lua">
|
||||
lua
|
||||
</option>
|
||||
|
||||
<option value="m">
|
||||
m
|
||||
</option>
|
||||
|
||||
<option value="mak">
|
||||
mak
|
||||
</option>
|
||||
|
||||
<option value="make">
|
||||
make
|
||||
</option>
|
||||
|
||||
<option value="makefile">
|
||||
makefile
|
||||
</option>
|
||||
|
||||
<option value="markdn">
|
||||
markdn
|
||||
</option>
|
||||
|
||||
<option value="markdown">
|
||||
markdown
|
||||
</option>
|
||||
|
||||
<option value="matlab">
|
||||
matlab
|
||||
</option>
|
||||
|
||||
<option value="md">
|
||||
md
|
||||
</option>
|
||||
|
||||
<option value="mdown">
|
||||
mdown
|
||||
</option>
|
||||
|
||||
<option value="mk">
|
||||
mk
|
||||
</option>
|
||||
|
||||
<option value="ml">
|
||||
ml
|
||||
</option>
|
||||
|
||||
<option value="mli">
|
||||
mli
|
||||
</option>
|
||||
|
||||
<option value="mll">
|
||||
mll
|
||||
</option>
|
||||
|
||||
<option value="mly">
|
||||
mly
|
||||
</option>
|
||||
|
||||
<option value="mm">
|
||||
mm
|
||||
</option>
|
||||
|
||||
<option value="mud">
|
||||
mud
|
||||
</option>
|
||||
|
||||
<option value="opml">
|
||||
opml
|
||||
</option>
|
||||
|
||||
<option value="p">
|
||||
p
|
||||
</option>
|
||||
|
||||
<option value="pas">
|
||||
pas
|
||||
</option>
|
||||
|
||||
<option value="patch">
|
||||
patch
|
||||
</option>
|
||||
|
||||
<option value="php">
|
||||
php
|
||||
</option>
|
||||
|
||||
<option value="php3">
|
||||
php3
|
||||
</option>
|
||||
|
||||
<option value="php4">
|
||||
php4
|
||||
</option>
|
||||
|
||||
<option value="php5">
|
||||
php5
|
||||
</option>
|
||||
|
||||
<option value="php7">
|
||||
php7
|
||||
</option>
|
||||
|
||||
<option value="phps">
|
||||
phps
|
||||
</option>
|
||||
|
||||
<option value="phpt">
|
||||
phpt
|
||||
</option>
|
||||
|
||||
<option value="phtml">
|
||||
phtml
|
||||
</option>
|
||||
|
||||
<option value="pl">
|
||||
pl
|
||||
</option>
|
||||
|
||||
<option value="pm">
|
||||
pm
|
||||
</option>
|
||||
|
||||
<option value="pod">
|
||||
pod
|
||||
</option>
|
||||
|
||||
<option value="podspec">
|
||||
podspec
|
||||
</option>
|
||||
|
||||
<option value="prawn">
|
||||
prawn
|
||||
</option>
|
||||
|
||||
<option value="properties">
|
||||
properties
|
||||
</option>
|
||||
|
||||
<option value="py">
|
||||
py
|
||||
</option>
|
||||
|
||||
<option value="py3">
|
||||
py3
|
||||
</option>
|
||||
|
||||
<option value="pyi">
|
||||
pyi
|
||||
</option>
|
||||
|
||||
<option value="pyw">
|
||||
pyw
|
||||
</option>
|
||||
|
||||
<option value="r">
|
||||
r
|
||||
</option>
|
||||
|
||||
<option value="rabl">
|
||||
rabl
|
||||
</option>
|
||||
|
||||
<option value="rails">
|
||||
rails
|
||||
</option>
|
||||
|
||||
<option value="rake">
|
||||
rake
|
||||
</option>
|
||||
|
||||
<option value="rb">
|
||||
rb
|
||||
</option>
|
||||
|
||||
<option value="rbx">
|
||||
rbx
|
||||
</option>
|
||||
|
||||
<option value="rd">
|
||||
rd
|
||||
</option>
|
||||
|
||||
<option value="re">
|
||||
re
|
||||
</option>
|
||||
|
||||
<option value="rest">
|
||||
rest
|
||||
</option>
|
||||
|
||||
<option value="rhtml">
|
||||
rhtml
|
||||
</option>
|
||||
|
||||
<option value="rjs">
|
||||
rjs
|
||||
</option>
|
||||
|
||||
<option value="rpy">
|
||||
rpy
|
||||
</option>
|
||||
|
||||
<option value="rs">
|
||||
rs
|
||||
</option>
|
||||
|
||||
<option value="rss">
|
||||
rss
|
||||
</option>
|
||||
|
||||
<option value="rst">
|
||||
rst
|
||||
</option>
|
||||
|
||||
<option value="ruby.rail">
|
||||
ruby.rail
|
||||
</option>
|
||||
|
||||
<option value="rxml">
|
||||
rxml
|
||||
</option>
|
||||
|
||||
<option value="s">
|
||||
s
|
||||
</option>
|
||||
|
||||
<option value="sass">
|
||||
sass
|
||||
</option>
|
||||
|
||||
<option value="sbt">
|
||||
sbt
|
||||
</option>
|
||||
|
||||
<option value="scala">
|
||||
scala
|
||||
</option>
|
||||
|
||||
<option value="scm">
|
||||
scm
|
||||
</option>
|
||||
|
||||
<option value="sconstruct">
|
||||
sconstruct
|
||||
</option>
|
||||
|
||||
<option value="sh">
|
||||
sh
|
||||
</option>
|
||||
|
||||
<option value="shtml">
|
||||
shtml
|
||||
</option>
|
||||
|
||||
<option value="simplecov">
|
||||
simplecov
|
||||
</option>
|
||||
|
||||
<option value="sql">
|
||||
sql
|
||||
</option>
|
||||
|
||||
<option value="sql.erb">
|
||||
sql.erb
|
||||
</option>
|
||||
|
||||
<option value="ss">
|
||||
ss
|
||||
</option>
|
||||
|
||||
<option value="sty">
|
||||
sty
|
||||
</option>
|
||||
|
||||
<option value="svg">
|
||||
svg
|
||||
</option>
|
||||
|
||||
<option value="swift">
|
||||
swift
|
||||
</option>
|
||||
|
||||
<option value="t">
|
||||
t
|
||||
</option>
|
||||
|
||||
<option value="tcl">
|
||||
tcl
|
||||
</option>
|
||||
|
||||
<option value="tex">
|
||||
tex
|
||||
</option>
|
||||
|
||||
<option value="textile">
|
||||
textile
|
||||
</option>
|
||||
|
||||
<option value="thor">
|
||||
thor
|
||||
</option>
|
||||
|
||||
<option value="tld">
|
||||
tld
|
||||
</option>
|
||||
|
||||
<option value="tmpl">
|
||||
tmpl
|
||||
</option>
|
||||
|
||||
<option value="tpl">
|
||||
tpl
|
||||
</option>
|
||||
|
||||
<option value="ts">
|
||||
ts
|
||||
</option>
|
||||
|
||||
<option value="tsx">
|
||||
tsx
|
||||
</option>
|
||||
|
||||
<option selected value="txt">
|
||||
txt
|
||||
</option>
|
||||
|
||||
<option value="wscript">
|
||||
wscript
|
||||
</option>
|
||||
|
||||
<option value="xhtml">
|
||||
xhtml
|
||||
</option>
|
||||
|
||||
<option value="xml">
|
||||
xml
|
||||
</option>
|
||||
|
||||
<option value="xsd">
|
||||
xsd
|
||||
</option>
|
||||
|
||||
<option value="xslt">
|
||||
xslt
|
||||
</option>
|
||||
|
||||
<option value="yaml">
|
||||
yaml
|
||||
</option>
|
||||
|
||||
<option value="yaws">
|
||||
yaws
|
||||
</option>
|
||||
|
||||
<option value="yml">
|
||||
yml
|
||||
</option>
|
||||
|
||||
<option value="zsh">
|
||||
zsh
|
||||
</option>
|
||||
|
||||
</select>
|
||||
<br />
|
||||
<input type="submit" value="Paste!" />
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user