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::{mime, Body, Error, Request, Response};
 | 
			
		||||
use pulldown_cmark::{html, Options, Parser};
 | 
			
		||||
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";
 | 
			
		||||
 | 
			
		||||
/// 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.
 | 
			
		||||
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> {
 | 
			
		||||
    // Get the request sent by the client. This hooks into the Compute@Edge runtime interface.
 | 
			
		||||
    let req = Request::from_client();
 | 
			
		||||
    // Filter request methods...
 | 
			
		||||
 | 
			
		||||
    // Filter out unrelated request methods.
 | 
			
		||||
    match req.get_method() {
 | 
			
		||||
        // Allow GET and HEAD requests.
 | 
			
		||||
        &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() {
 | 
			
		||||
        "/" => Request::get("http://nora.codes/edgeblog/index.md"),
 | 
			
		||||
        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) {
 | 
			
		||||
        Err(_e) => Body::new(),
 | 
			
		||||
        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) {
 | 
			
		||||
        Err(_e) => Body::new(),
 | 
			
		||||
        Ok(mut r) => r.take_body(),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Write the header into the synthetic body
 | 
			
		||||
    let mut md_assembled = String::new();
 | 
			
		||||
    header_body.read_to_string(&mut md_assembled)?;
 | 
			
		||||
    // Write the footer into the synthetic body
 | 
			
		||||
    md_assembled.push_str("\n");
 | 
			
		||||
    footer_body.read_to_string(&mut md_assembled)?;
 | 
			
		||||
 | 
			
		||||
    // Get the geoip info for the client, if possible.
 | 
			
		||||
    const UNKNOWN_LOCATION_STRING: &str = "unknown";
 | 
			
		||||
    let geotext: String = match req.get_client_ip_addr() {
 | 
			
		||||
        Some(ip) => match fastly::geo::geo_lookup(ip) {
 | 
			
		||||
            None => "an undisclosed location".into(),
 | 
			
		||||
            None => UNKNOWN_LOCATION_STRING.into(),
 | 
			
		||||
            Some(geo) => format!(
 | 
			
		||||
                "AS{} '{}', in {}",
 | 
			
		||||
                geo.as_number(),
 | 
			
		||||
| 
						 | 
				
			
			@ -65,24 +97,11 @@ fn main() -> Result<(), Error> {
 | 
			
		|||
            )
 | 
			
		||||
            .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.
 | 
			
		||||
    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(());
 | 
			
		||||
    }
 | 
			
		||||
    md_assembled.push_str(&format!("\n<h5> Your provider: {} </h5>", geotext));
 | 
			
		||||
 | 
			
		||||
    // 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 mut client_body = beresp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue