Skip to content

Commit

Permalink
Merge pull request #367 from manikmagar/image-src-path-fix
Browse files Browse the repository at this point in the history
Prevent image source path from breaking
  • Loading branch information
jonbullock committed Aug 14, 2017
2 parents 76f5ecb + 1a80c02 commit 6d2f51d
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 7 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ext {
jsonSimpleVersion = '1.1.1'
jade4jVersion = '1.2.5'
mockitoVersion = '1.10.19'
jsoupVersion = '1.10.2'
}

dependencies {
Expand All @@ -68,6 +69,7 @@ dependencies {
compile group: 'ch.qos.logback', name: 'logback-classic', version: logbackVersion
compile group: 'ch.qos.logback', name: 'logback-core', version: logbackVersion
compile group: 'de.neuland-bfi', name: 'jade4j', version: jade4jVersion
compile group: 'org.jsoup', name:'jsoup', version: jsoupVersion
testCompile group: 'junit', name: 'junit', version: junitVersion
testCompile group: 'org.assertj', name: 'assertj-core', version: assertjCoreVersion
testCompile group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
Expand Down
18 changes: 11 additions & 7 deletions src/main/java/org/jbake/app/Crawler.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
package org.jbake.app;


import com.orientechnologies.orient.core.record.impl.ODocument;
import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.io.FilenameUtils;
import org.jbake.app.ConfigUtil.Keys;
import org.jbake.app.Crawler.Attributes.Status;
import org.jbake.model.DocumentAttributes;
import org.jbake.model.DocumentStatus;
import org.jbake.model.DocumentTypes;
import org.jbake.util.HtmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

import static java.io.File.separator;
import com.orientechnologies.orient.core.record.impl.ODocument;

/**
* Crawls a file system looking for content.
Expand Down Expand Up @@ -179,6 +179,10 @@ private void crawlSourceFile(final File sourceFile, final String sha1, final Str
if (config.getBoolean(Keys.URI_NO_EXTENSION)) {
fileContents.put(Attributes.NO_EXTENSION_URI, uri.replace("/index.html", "/"));
}


// Prevent image source url's from breaking
HtmlUtil.fixImageSourceUrls(fileContents,config);

ODocument doc = new ODocument(documentType);
doc.fields(fileContents);
Expand Down
82 changes: 82 additions & 0 deletions src/main/java/org/jbake/util/HtmlUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.jbake.util;

import java.util.Map;

import org.apache.commons.configuration.CompositeConfiguration;
import org.jbake.app.ConfigUtil.Keys;
import org.jbake.app.Crawler.Attributes;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
*
* @author Manik Magar
*
*/
public class HtmlUtil {

/**
* Image paths are specified as w.r.t. assets folder. This function prefix site host to all img src except
* the ones that starts with http://, https://.
*
* If image path starts with "./", i.e. relative to the source file, then it first replace that with output file directory and the add site host.
*
* @param fileContents
*/
public static void fixImageSourceUrls(Map<String, Object> fileContents, CompositeConfiguration config){

String htmlContent = fileContents.get(Attributes.BODY).toString();

String siteHost = config.getString(Keys.SITE_HOST);

String uri = fileContents.get(Attributes.URI).toString();

if(fileContents.get(Attributes.NO_EXTENSION_URI) != null){
uri = fileContents.get(Attributes.NO_EXTENSION_URI).toString();

//remove trailing "/"
if(uri.endsWith("/")) {
uri = uri.substring(0, uri.length() - 1);
}

}

if(uri.contains("/")){
//strip that file name, leaving end "/"
uri = uri.substring(0, uri.lastIndexOf("/") + 1);
}

Document document = Jsoup.parseBodyFragment(htmlContent);

Elements allImgs = document.getElementsByTag("img");

for (Element img : allImgs) {
String source = img.attr("src");

if(source.startsWith("./")){
// image relative to current content is specified,
// lets add current url to it.
source = source.replaceFirst("./", uri);
}

// Now add the root path
if(!source.startsWith("http://")
&& !source.startsWith("https://")){

if (!siteHost.endsWith("/") && !source.startsWith("/")) siteHost = siteHost.concat("/");

String fullUrl = siteHost + source;

img.attr("src", fullUrl);

}
}


//Use body().html() to prevent adding <body></body> from parsed fragment.
fileContents.put(Attributes.BODY, document.body().html());
}

}
149 changes: 149 additions & 0 deletions src/test/java/org/jbake/util/HtmlUtilTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package org.jbake.util;

import static org.assertj.core.api.Assertions.*;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.configuration.CompositeConfiguration;
import org.jbake.app.ConfigUtil;
import org.jbake.app.Crawler.Attributes;
import org.jbake.util.HtmlUtil;
import org.junit.Before;
import org.junit.Test;



public class HtmlUtilTest {

private CompositeConfiguration config;

@Before
public void setUp() throws Exception{
config = ConfigUtil.load(new File(this.getClass().getResource("/fixture").getFile()));
}

@Test
public void shouldNotAddBodyHTMLElement(){
Map<String, Object> fileContent = new HashMap<String, Object>();
fileContent.put(Attributes.ROOTPATH, "../../../");
fileContent.put(Attributes.URI, "blog/2017/05/first_post.html");
fileContent.put(Attributes.BODY, "<div> Test <img src='blog/2017/05/first.jpg' /></div>");

HtmlUtil.fixImageSourceUrls(fileContent, config);

String body = fileContent.get(Attributes.BODY).toString();

assertThat(body).doesNotContain("<body>");
assertThat(body).doesNotContain("</body>");

}

@Test
public void shouldAddRootpath(){
Map<String, Object> fileContent = new HashMap<String, Object>();
fileContent.put(Attributes.ROOTPATH, "../../../");
fileContent.put(Attributes.URI, "blog/2017/05/first_post.html");
fileContent.put(Attributes.BODY, "<div> Test <img src='blog/2017/05/first.jpg' /></div>");

HtmlUtil.fixImageSourceUrls(fileContent, config);

String body = fileContent.get(Attributes.BODY).toString();

assertThat(body).contains("src=\"http://www.jbake.org/blog/2017/05/first.jpg\"");

}

@Test
public void shouldAddContentpath(){
Map<String, Object> fileContent = new HashMap<String, Object>();
fileContent.put(Attributes.ROOTPATH, "../../../");
fileContent.put(Attributes.URI, "blog/2017/05/first_post.html");
fileContent.put(Attributes.BODY, "<div> Test <img src='./first.jpg' /></div>");

HtmlUtil.fixImageSourceUrls(fileContent, config);

String body = fileContent.get(Attributes.BODY).toString();

assertThat(body).contains("src=\"http://www.jbake.org/blog/2017/05/first.jpg\"");

}

@Test
public void shouldNotAddRootPath(){
Map<String, Object> fileContent = new HashMap<String, Object>();
fileContent.put(Attributes.ROOTPATH, "../../../");
fileContent.put(Attributes.URI, "blog/2017/05/first_post.html");
fileContent.put(Attributes.BODY, "<div> Test <img src='/blog/2017/05/first.jpg' /></div>");

HtmlUtil.fixImageSourceUrls(fileContent,config);

String body = fileContent.get(Attributes.BODY).toString();

assertThat(body).contains("src=\"http://www.jbake.org/blog/2017/05/first.jpg\"");

}

@Test
public void shouldAddRootPathForNoExtension(){
Map<String, Object> fileContent = new HashMap<String, Object>();
fileContent.put(Attributes.ROOTPATH, "../../../");
fileContent.put(Attributes.URI, "blog/2017/05/first_post.html");
fileContent.put(Attributes.NO_EXTENSION_URI, "blog/2017/05/first_post/");
fileContent.put(Attributes.BODY, "<div> Test <img src='blog/2017/05/first.jpg' /></div>");

HtmlUtil.fixImageSourceUrls(fileContent, config);

String body = fileContent.get(Attributes.BODY).toString();

assertThat(body).contains("src=\"http://www.jbake.org/blog/2017/05/first.jpg\"");

}

@Test
public void shouldAddContentPathForNoExtension(){
Map<String, Object> fileContent = new HashMap<String, Object>();
fileContent.put(Attributes.ROOTPATH, "../../../");
fileContent.put(Attributes.URI, "blog/2017/05/first_post.html");
fileContent.put(Attributes.NO_EXTENSION_URI, "blog/2017/05/first_post/");
fileContent.put(Attributes.BODY, "<div> Test <img src='./first.jpg' /></div>");

HtmlUtil.fixImageSourceUrls(fileContent, config);

String body = fileContent.get(Attributes.BODY).toString();

assertThat(body).contains("src=\"http://www.jbake.org/blog/2017/05/first.jpg\"");
}

@Test
public void shouldNotChangeForHTTP(){
Map<String, Object> fileContent = new HashMap<String, Object>();
fileContent.put(Attributes.ROOTPATH, "../../../");
fileContent.put(Attributes.URI, "blog/2017/05/first_post.html");
fileContent.put(Attributes.NO_EXTENSION_URI, "blog/2017/05/first_post/");
fileContent.put(Attributes.BODY, "<div> Test <img src='http://example.com/first.jpg' /></div>");

HtmlUtil.fixImageSourceUrls(fileContent, config);

String body = fileContent.get(Attributes.BODY).toString();

assertThat(body).contains("src=\"http://example.com/first.jpg\"");

}

@Test
public void shouldNotChangeForHTTPS(){
Map<String, Object> fileContent = new HashMap<String, Object>();
fileContent.put(Attributes.ROOTPATH, "../../../");
fileContent.put(Attributes.URI, "blog/2017/05/first_post.html");
fileContent.put(Attributes.NO_EXTENSION_URI, "blog/2017/05/first_post/");
fileContent.put(Attributes.BODY, "<div> Test <img src='https://example.com/first.jpg' /></div>");

HtmlUtil.fixImageSourceUrls(fileContent, config);

String body = fileContent.get(Attributes.BODY).toString();

assertThat(body).contains("src=\"https://example.com/first.jpg\"");
}
}

0 comments on commit 6d2f51d

Please sign in to comment.