Support images and embeds properly.
This commit is contained in:
		
							parent
							
								
									9829ba7310
								
							
						
					
					
						commit
						338e22dc69
					
				
							
								
								
									
										69
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										69
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
					@ -1,11 +1,12 @@
 | 
				
			||||||
//! Default Compute@Edge template program.
 | 
					//! Compute@Edge service which renders markdown from external sources.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use fastly::http::{header, Method, StatusCode};
 | 
					use fastly::http::{header, Method, StatusCode};
 | 
				
			||||||
use fastly::{mime, Body, Error, Request, Response};
 | 
					use fastly::{mime, Body, Error, Request, Response};
 | 
				
			||||||
use pulldown_cmark::{html, Options, Parser};
 | 
					use pulldown_cmark::{html, Options, Parser};
 | 
				
			||||||
use std::io::Read;
 | 
					use std::io::Read;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The configured backend name.
 | 
					/// The configured backend name. This is set up in the Fastly interface, and in fastly.toml
 | 
				
			||||||
 | 
					/// for local development.
 | 
				
			||||||
const BACKEND_NAME: &str = "upstream_ssl";
 | 
					const BACKEND_NAME: &str = "upstream_ssl";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The URL of the header markdown content.
 | 
					/// The URL of the header markdown content.
 | 
				
			||||||
| 
						 | 
					@ -13,9 +14,12 @@ const HEADER_URL: &str = "http://nora.codes/edgeblog/_header.md";
 | 
				
			||||||
/// The URL of the footer markdown content.
 | 
					/// The URL of the footer markdown content.
 | 
				
			||||||
const FOOTER_URL: &str = "http://nora.codes/edgeblog/_footer.md";
 | 
					const FOOTER_URL: &str = "http://nora.codes/edgeblog/_footer.md";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// This function is invoked for every request. If it returns Err(), the user will see a 500.
 | 
				
			||||||
fn main() -> Result<(), Error> {
 | 
					fn main() -> Result<(), Error> {
 | 
				
			||||||
 | 
					    // Get the request sent by the client. This hooks into the Compute@Edge runtime interface.
 | 
				
			||||||
    let req = Request::from_client();
 | 
					    let req = Request::from_client();
 | 
				
			||||||
    // Filter request methods...
 | 
					
 | 
				
			||||||
 | 
					    // Filter out unrelated request methods.
 | 
				
			||||||
    match req.get_method() {
 | 
					    match req.get_method() {
 | 
				
			||||||
        // Allow GET and HEAD requests.
 | 
					        // Allow GET and HEAD requests.
 | 
				
			||||||
        &Method::GET | &Method::HEAD => (),
 | 
					        &Method::GET | &Method::HEAD => (),
 | 
				
			||||||
| 
						 | 
					@ -30,33 +34,61 @@ fn main() -> Result<(), Error> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Rewrite the / path to index.md, and construct a Request
 | 
					    // Rewrite the / path to index.md, and construct a Request for the main body content.
 | 
				
			||||||
    let upstream_req = match req.get_path() {
 | 
					    let upstream_req = match req.get_path() {
 | 
				
			||||||
        "/" => Request::get("http://nora.codes/edgeblog/index.md"),
 | 
					        "/" => Request::get("http://nora.codes/edgeblog/index.md"),
 | 
				
			||||||
        path => Request::get(format!("http://nora.codes/edgeblog/{}", path)),
 | 
					        path => Request::get(format!("http://nora.codes/edgeblog/{}", path)),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get the data for the header portion of the page
 | 
					    // Get the data for the body portion of the page, and write the content into the Markdown
 | 
				
			||||||
 | 
					    // document.
 | 
				
			||||||
 | 
					    // This backend response is used as the template for the synthetic response.
 | 
				
			||||||
 | 
					    let mut beresp = upstream_req.send(BACKEND_NAME)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // It's important to set Markdown's MIME type as "text" on your webserver;
 | 
				
			||||||
 | 
					    // I used "text/markdown".
 | 
				
			||||||
 | 
					    // Here, we check whether or not the object being requested is text. If so, we'll render it
 | 
				
			||||||
 | 
					    // inline; otherwise, we'll serve it as is. This allows supporting images, other documents,
 | 
				
			||||||
 | 
					    // and so forth without any extra effort.
 | 
				
			||||||
 | 
					    if beresp
 | 
				
			||||||
 | 
					        .get_content_type()
 | 
				
			||||||
 | 
					        .map(|mime| mime.type_() != mime::TEXT)
 | 
				
			||||||
 | 
					        .unwrap_or(true)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        beresp.send_to_client();
 | 
				
			||||||
 | 
					        return Ok(());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Get the data for the header portion of the page, making a backend request to the origin
 | 
				
			||||||
 | 
					    // server. This will be cached.
 | 
				
			||||||
    let mut header_body = match Request::get(HEADER_URL).send(BACKEND_NAME) {
 | 
					    let mut header_body = match Request::get(HEADER_URL).send(BACKEND_NAME) {
 | 
				
			||||||
        Err(_e) => Body::new(),
 | 
					        Err(_e) => Body::new(),
 | 
				
			||||||
        Ok(mut r) => r.take_body(),
 | 
					        Ok(mut r) => r.take_body(),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get the data for the footer portion of the page
 | 
					    // Start off the Markdown document with the header content.
 | 
				
			||||||
 | 
					    let mut md_assembled = String::new();
 | 
				
			||||||
 | 
					    header_body.read_to_string(&mut md_assembled)?;
 | 
				
			||||||
 | 
					    md_assembled.push_str("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beresp.take_body().read_to_string(&mut md_assembled)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Get the data for the footer portion of the page, making a backend request to the origin
 | 
				
			||||||
 | 
					    // server. This will be cached.
 | 
				
			||||||
    let mut footer_body = match Request::get(FOOTER_URL).send(BACKEND_NAME) {
 | 
					    let mut footer_body = match Request::get(FOOTER_URL).send(BACKEND_NAME) {
 | 
				
			||||||
        Err(_e) => Body::new(),
 | 
					        Err(_e) => Body::new(),
 | 
				
			||||||
        Ok(mut r) => r.take_body(),
 | 
					        Ok(mut r) => r.take_body(),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Write the header into the synthetic body
 | 
					    // Write the footer into the synthetic body
 | 
				
			||||||
    let mut md_assembled = String::new();
 | 
					 | 
				
			||||||
    header_body.read_to_string(&mut md_assembled)?;
 | 
					 | 
				
			||||||
    md_assembled.push_str("\n");
 | 
					    md_assembled.push_str("\n");
 | 
				
			||||||
 | 
					    footer_body.read_to_string(&mut md_assembled)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get the geoip info for the client, if possible.
 | 
					    // Get the geoip info for the client, if possible.
 | 
				
			||||||
 | 
					    const UNKNOWN_LOCATION_STRING: &str = "unknown";
 | 
				
			||||||
    let geotext: String = match req.get_client_ip_addr() {
 | 
					    let geotext: String = match req.get_client_ip_addr() {
 | 
				
			||||||
        Some(ip) => match fastly::geo::geo_lookup(ip) {
 | 
					        Some(ip) => match fastly::geo::geo_lookup(ip) {
 | 
				
			||||||
            None => "an undisclosed location".into(),
 | 
					            None => UNKNOWN_LOCATION_STRING.into(),
 | 
				
			||||||
            Some(geo) => format!(
 | 
					            Some(geo) => format!(
 | 
				
			||||||
                "AS{} '{}', in {}",
 | 
					                "AS{} '{}', in {}",
 | 
				
			||||||
                geo.as_number(),
 | 
					                geo.as_number(),
 | 
				
			||||||
| 
						 | 
					@ -65,24 +97,11 @@ fn main() -> Result<(), Error> {
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .into(),
 | 
					            .into(),
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        None => "an undisclosed location".into(),
 | 
					        None => UNKNOWN_LOCATION_STRING.into(),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get the content of the page itself. If this fails, pass on the failure.
 | 
					    md_assembled.push_str(&format!("\n<h5> Your provider: {} </h5>", geotext));
 | 
				
			||||||
    let mut beresp = upstream_req.send(BACKEND_NAME)?;
 | 
					 | 
				
			||||||
    if beresp.get_status() == StatusCode::OK {
 | 
					 | 
				
			||||||
        beresp.take_body().read_to_string(&mut md_assembled)?;
 | 
					 | 
				
			||||||
        md_assembled = md_assembled.replace("{{geo}}", &geotext);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        beresp.send_to_client();
 | 
					 | 
				
			||||||
        return Ok(());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Write the footer into the synthetic body
 | 
					 | 
				
			||||||
    md_assembled.push_str("\n");
 | 
					 | 
				
			||||||
    footer_body.read_to_string(&mut md_assembled)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let md_assembled = md_assembled.replace("{{geo}}", &geotext);
 | 
					 | 
				
			||||||
    let parser = Parser::new_ext(&md_assembled, Options::empty());
 | 
					    let parser = Parser::new_ext(&md_assembled, Options::empty());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut client_body = beresp
 | 
					    let mut client_body = beresp
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue