lightbody / browsermob-proxy

A free utility to help web developers watch and manipulate network traffic from their AJAX applications.
http://bmp.lightbody.net
Apache License 2.0
2.17k stars 659 forks source link

Can HAR files produced by browsermob-proxy be deserialised back to Har object? #404

Closed gitgrimbo closed 8 years ago

gitgrimbo commented 8 years ago

Similar to #143, I would like to know if it's possible to deserialise a HAR file into the Har object?

I have had to do the following to get the Har object created due to the following issues:

(note that my HarCookieDateDeserializer does nothing at the moment)

    Har loadHarFromResource(final String resourceName) throws JsonParseException, JsonMappingException, IOException {
        InputStream in = getClass().getResourceAsStream(resourceName);
        ObjectMapper m = new ObjectMapper();
        SimpleModule module = new SimpleModule("MyModule", new Version(1, 0, 0, null, null, null)) {
            public void setupModule(final SetupContext context) {
                context.setMixInAnnotations(HarNameValuePair.class, HarNameValuePairMixin.class);
                context.setMixInAnnotations(HarNameVersion.class, HarNameVersionMixin.class);
                context.setMixInAnnotations(HarCookie.class, HarCookieMixin.class);
                context.setMixInAnnotations(HarEntry.class, HarEntryMixin.class);
            }
        };
        m.registerModule(module);
        return m.readValue(in, Har.class);
    }

    static abstract class HarNameValuePairMixin {
        HarNameValuePairMixin(@JsonProperty("name") final String name, @JsonProperty("value") final String value) {}
    }

    static abstract class HarNameVersionMixin {
        HarNameVersionMixin(@JsonProperty("name") final String name, @JsonProperty("value") final String value) {}
    }

    static abstract class HarCookieMixin {
        @JsonProperty("expires")
        @JsonDeserialize(using = HarCookieDateDeserializer.class)
        Date expires;
    }

    static abstract class HarEntryMixin {
        @JsonProperty("time")
        @JsonIgnore
        abstract long getTime();
    }

    static class HarCookieDateDeserializer extends JsonDeserializer<Date> {
        public Date deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
            return null;
        }
    }

And without the HarCookieDateDeserializer I get this error:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of java.util.Date from String value ("292269008-02-13T06:07:56.897Z"): not a valid representation (error: Failed to parse Date value '292269008-02-13T06:07:56.897Z': Can not parse date "292269008-02-13T06:07:56.897Z": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))
 at [Source: java.io.BufferedInputStream@4c0bc4; line: 1, column: 1382] (through reference chain: net.lightbody.bmp.core.har.Har["log"]->net.lightbody.bmp.core.har.HarLog["entries"]->java.util.ArrayList[0]->net.lightbody.bmp.core.har.HarEntry["response"]->net.lightbody.bmp.core.har.HarResponse["cookies"]->java.util.ArrayList[0]->net.lightbody.bmp.core.har.HarCookie["expires"])
    at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:74)
    at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:923)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseDate(StdDeserializer.java:788)
    at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateBasedDeserializer._parseDate(DateDeserializers.java:175)
    at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:261)
jekh commented 8 years ago

They should be able to be deserialized; for example, the HAR viewer parses BMP HARs successfully. BMP's Har classes aren't really designed to deserialize, as there is no reason I'm aware of for the proxy to do so.

Are there any existing Java libraries for HAR parsing that you could leverage?

gitgrimbo commented 8 years ago

Hi, I'm not questioning the validity of the HAR JSON that is produced by the BMP Har classes, I was more wondering if the same JSON could be deserialised back into the BMP Har classes.

If the answer is that BMP is essentially 'serialise-only' for HAR files then I'm happy with that as an answer and will look towards other HAR parsers/HAR model classes to meet that requirement.

jpereira06 commented 8 years ago

Take a look at https://github.com/sdstoehr/har-reader

jekh commented 8 years ago

@gitgrimbo - Yes, BMP's Har class tree is designed for serialization only. I'd recommend using a HAR library designed for deserialization, such as the one @jpereira06 suggested.

evidana commented 8 years ago

@gitgrimbo I ran into the same thing with the expiry date in the JSESSIONID cookie. I did a string replace for that one value to some meaningful year and the rest worked fine. I am using the Browsermob API to stand up the proxy then grabbing the HAR. Tough part was that I had to stand up a different library for the Har class that was able to be serialized/deserialized.

<dependency>
       <groupId>de.sstoehr</groupId>
       <artifactId>har-reader</artifactId>
       <version>2.0.0</version>
</dependency>
// basic example
private Har retrieveHar() {
        HttpClient client = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet("http://localhost:8080/proxy/8081/har");
        HarReader harReader = new HarReader();
        try {
            org.apache.http.HttpResponse response = client.execute(httpGet);
            HttpEntity entity = response.getEntity();
            String responseString = EntityUtils.toString(entity);
            // the stupid cookie with a crazy expire year on it
            String cleanResponse = responseString.replace("292269008","2012");
            bmpHar = harReader.readFromString(cleanResponse);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return bmpHar;
    }