Skip to content

Commit

Permalink
[#1516] change proxy http header format.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaehong-kim committed Sep 12, 2017
1 parent 55c3f78 commit 694c4a8
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@

import com.navercorp.pinpoint.common.util.StringUtils;

import java.util.List;

/**
* @author jaehong.kim
*/
public class ProxyHttpHeaderParser {
private final ProxyTimeUnit nginxUnit = new NginxTimeUnit();
private final ProxyTimeUnit apacheUnit = new ApacheTimeUnit();
private final ProxyTimeUnit appUnit = new AppTimeUnit();

public ProxyHttpHeader parse(final int type, final String value) {
final ProxyHttpHeader header = new ProxyHttpHeader(type);
if (value == null) {
Expand All @@ -33,11 +35,11 @@ public ProxyHttpHeader parse(final int type, final String value) {
}

if (type == ProxyHttpHeader.TYPE_APP) {
parseAppFormat(header, value);
parseFormat(header, value, appUnit);
} else if (type == ProxyHttpHeader.TYPE_NGINX) {
parseNginxFormat(header, value);
parseFormat(header, value, nginxUnit);
} else if (type == ProxyHttpHeader.TYPE_APACHE) {
parseApacheHttpdFormat(header, value);
parseFormat(header, value, apacheUnit);
} else {
header.setValid(false);
header.setCause("unknown type");
Expand All @@ -46,27 +48,24 @@ public ProxyHttpHeader parse(final int type, final String value) {
return header;
}

void parseApacheHttpdFormat(final ProxyHttpHeader header, final String value) {
void parseFormat(final ProxyHttpHeader header, final String value, final ProxyTimeUnit proxyTimeUnit) {
for (String token : StringUtils.tokenizeToStringList(value, " ")) {
if (token.startsWith("t=")) {
// convert to milliseconds from microseconds.
final int length = token.length() - 3;
if (length > 2) {
final long receivedTimeMillis = ApacheUnit.toReceivedTimeMillis(token.substring(2));
if (receivedTimeMillis > 0) {
header.setReceivedTimeMillis(receivedTimeMillis);
header.setValid(true);
continue;
}
final long receivedTimeMillis = proxyTimeUnit.toReceivedTimeMillis(token.substring(2));
if (receivedTimeMillis > 0) {
header.setReceivedTimeMillis(receivedTimeMillis);
header.setValid(true);
} else {
// stop.
header.setValid(false);
header.setCause("invalid received time");
return;
}
header.setValid(false);
header.setCause("invalid received time");
return;
} else if (token.startsWith("D=")) {
final long durationTimeMicroseconds = ApacheUnit.toDurationTimeMicros(token.substring(2));
final long durationTimeMicroseconds = proxyTimeUnit.toDurationTimeMicros(token.substring(2));
if (durationTimeMicroseconds > 0) {
header.setDurationTimeMicroseconds((int) durationTimeMicroseconds);
continue;
}
} else if (token.startsWith("i=")) {
try {
Expand All @@ -86,54 +85,43 @@ void parseApacheHttpdFormat(final ProxyHttpHeader header, final String value) {
}
} catch (NumberFormatException ignored) {
}
} else if (token.startsWith("app=")) {
final String app = token.substring(4).trim();
if (!app.isEmpty()) {
header.setApp(app);
}
}
}
}

void parseNginxFormat(final ProxyHttpHeader header, final String value) {
final List<String> tokens = StringUtils.tokenizeToStringList(value, " ");
if (tokens.size() >= 1) {
// first token is receivedTimeMillis.
final long receivedTimeMillis = NginxUnit.toReceivedTimeMillis(tokens.get(0));
if (receivedTimeMillis > 0) {
header.setReceivedTimeMillis(receivedTimeMillis);
header.setValid(true);
} else {
header.setValid(false);
header.setCause("invalid received time");
return;
}
}
// for testcase.
ProxyTimeUnit getNginxUnit() {
return nginxUnit;
}

if (tokens.size() >= 2) {
final long durationTimeMicroseconds = NginxUnit.toDurationTimeMicros(tokens.get(1));
if (durationTimeMicroseconds > 0) {
header.setDurationTimeMicroseconds((int) durationTimeMicroseconds);
}
}
// for testcase.
ProxyTimeUnit getApacheUnit() {
return apacheUnit;
}

void parseAppFormat(final ProxyHttpHeader header, final String value) {
final List<String> tokens = StringUtils.tokenizeToStringList(value, " ");
if (tokens.size() >= 1) {
final long receivedTimeMillis = AppUnit.toReceivedTimeMillis(tokens.get(0));
if (receivedTimeMillis > 0) {
header.setReceivedTimeMillis(receivedTimeMillis);
header.setValid(true);
} else {
header.setValid(false);
header.setCause("invalid received time");
return;
}
}
// for testcase.
ProxyTimeUnit getAppUnit() {
return appUnit;
}

if (tokens.size() >= 2) {
header.setApp(tokens.get(1));
}
interface ProxyTimeUnit {
long toReceivedTimeMillis(final String value);

int toDurationTimeMicros(final String value);
}

static class NginxUnit {
static long toReceivedTimeMillis(final String value) {
private class NginxTimeUnit implements ProxyTimeUnit {

public NginxTimeUnit() {
}

@Override
public long toReceivedTimeMillis(final String value) {
if (value == null) {
return 0;
}
Expand All @@ -154,7 +142,8 @@ static long toReceivedTimeMillis(final String value) {
return 0;
}

static long toDurationTimeMicros(final String value) {
@Override
public int toDurationTimeMicros(final String value) {
if (value == null) {
return 0;
}
Expand All @@ -169,16 +158,17 @@ static long toDurationTimeMicros(final String value) {
}
try {
// to microseconds
return Long.parseLong(value.substring(0, millisPosition) + value.substring(millisPosition + 1)) * 1000;
return Integer.parseInt(value.substring(0, millisPosition) + value.substring(millisPosition + 1)) * 1000;
} catch (NumberFormatException ignored) {
}
}
return 0;
}
}

static class ApacheUnit {
static long toReceivedTimeMillis(final String value) {
private class ApacheTimeUnit implements ProxyTimeUnit {
@Override
public long toReceivedTimeMillis(final String value) {
if (value == null) {
return 0;
}
Expand All @@ -194,21 +184,23 @@ static long toReceivedTimeMillis(final String value) {
return 0;
}

static long toDurationTimeMicros(final String value) {
@Override
public int toDurationTimeMicros(final String value) {
if (value == null) {
return 0;
}

try {
return Long.parseLong(value);
return Integer.parseInt(value);
} catch (NumberFormatException ignored) {
}
return 0;
}
}

static class AppUnit {
static long toReceivedTimeMillis(final String value) {
private class AppTimeUnit implements ProxyTimeUnit {
@Override
public long toReceivedTimeMillis(final String value) {
if (value == null) {
return 0;
}
Expand All @@ -220,5 +212,10 @@ static long toReceivedTimeMillis(final String value) {
}
return 0;
}

@Override
public int toDurationTimeMicros(String value) {
return 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public void parseApacheHttpd() throws Exception {
assertEquals(12345, tvalue.getIntValue2());
assertEquals(99, tvalue.getByteValue1());
assertEquals(1, tvalue.getByteValue2());
System.out.println("");
}

@Test
Expand Down Expand Up @@ -104,7 +105,7 @@ public void parseApacheHttpdTooShotReceivedTime() throws Exception {
@Test
public void parseNginx() throws Exception {
ProxyHttpHeaderParser parser = new ProxyHttpHeaderParser();
String value = "1504248328.423 0.123";
String value = "t=1504248328.423 D=0.123";
ProxyHttpHeader proxyHttpHeader = parser.parse(ProxyHttpHeader.TYPE_NGINX, value);
assertTrue(proxyHttpHeader.isValid());
assertEquals(1504248328423L, proxyHttpHeader.getReceivedTimeMillis());
Expand All @@ -122,7 +123,7 @@ public void parseNginx() throws Exception {
@Test
public void parseNginxMsec() throws Exception {
ProxyHttpHeaderParser parser = new ProxyHttpHeaderParser();
String value = "1504248328.423";
String value = "t=1504248328.423";
ProxyHttpHeader proxyHttpHeader = parser.parse(ProxyHttpHeader.TYPE_NGINX, value);
assertTrue(proxyHttpHeader.isValid());
assertEquals(1504248328423L, proxyHttpHeader.getReceivedTimeMillis());
Expand All @@ -141,7 +142,7 @@ public void parseNginxMsec() throws Exception {
public void parseApp() throws Exception {
ProxyHttpHeaderParser parser = new ProxyHttpHeaderParser();
final long currentTimeMillis = System.currentTimeMillis();
String value = String.valueOf(currentTimeMillis);
String value = "t=" + currentTimeMillis;
ProxyHttpHeader proxyHttpHeader = parser.parse(ProxyHttpHeader.TYPE_APP, value);
assertTrue(proxyHttpHeader.isValid());
assertEquals(currentTimeMillis, proxyHttpHeader.getReceivedTimeMillis());
Expand All @@ -160,67 +161,74 @@ public void parseApp() throws Exception {
public void parseTimestampInvalidValue() throws Exception {
ProxyHttpHeaderParser parser = new ProxyHttpHeaderParser();
final long currentTimeMillis = System.currentTimeMillis();
String value = String.valueOf(Long.MAX_VALUE) + String.valueOf(Long.MAX_VALUE);
String value = "t=" + String.valueOf(Long.MAX_VALUE) + String.valueOf(Long.MAX_VALUE);
ProxyHttpHeader proxyHttpHeader = parser.parse(ProxyHttpHeader.TYPE_APP, value);
assertFalse(proxyHttpHeader.isValid());
}

@Test
public void parseUnknown() throws Exception {
ProxyHttpHeaderParser parser = new ProxyHttpHeaderParser();
String value = "x=" + System.currentTimeMillis() + "999";
ProxyHttpHeader proxyHttpHeader = parser.parse(ProxyHttpHeader.TYPE_APP, value);
assertFalse(proxyHttpHeader.isValid());
assertEquals(0, proxyHttpHeader.getReceivedTimeMillis());
assertEquals(-1, proxyHttpHeader.getDurationTimeMicroseconds());
assertEquals(-1, proxyHttpHeader.getIdlePercent());
assertEquals(-1, proxyHttpHeader.getBusyPercent());
assertEquals(AnnotationKey.PROXY_HTTP_HEADER, proxyHttpHeader.getAnnotationKey());
LongIntIntByteByteStringValue tvalue = (LongIntIntByteByteStringValue) proxyHttpHeader.getAnnotationValue();
assertEquals(0, tvalue.getLongValue());
assertEquals(-1, tvalue.getIntValue2());
assertEquals(-1, tvalue.getByteValue1());
assertEquals(-1, tvalue.getByteValue2());
// missing t=
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APP, "x=99999").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APP, "D=0.00").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APP, "i=100").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APP, "b=100").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APP, "app=foo-bar").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APACHE, "D=100 i=1 b=99").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_NGINX, "D=0.00").isValid());

// invalid t=
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APP, "t=A10101010").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APP, "t=0").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APACHE, "t=0").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APACHE, "t=10").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_APACHE, "t=100").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_NGINX, "t=0").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_NGINX, "t=10").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_NGINX, "t=10.0").isValid());
assertFalse(parser.parse(ProxyHttpHeader.TYPE_NGINX, "t=10.00").isValid());
}

@Test
public void toReceivedTimeMillis() throws Exception {
ProxyHttpHeaderParser parser = new ProxyHttpHeaderParser();
assertEquals(1504230492763L, ProxyHttpHeaderParser.NginxUnit.toReceivedTimeMillis("1504230492.763"));
assertEquals(1504244246860L, ProxyHttpHeaderParser.ApacheUnit.toReceivedTimeMillis("1504244246860824"));
assertEquals(1504230492763L, ProxyHttpHeaderParser.AppUnit.toReceivedTimeMillis("1504230492763"));

assertEquals(1504230492763L, parser.getNginxUnit().toReceivedTimeMillis("1504230492.763"));
assertEquals(1504244246860L, parser.getApacheUnit().toReceivedTimeMillis("1504244246860824"));
assertEquals(1504230492763L, parser.getAppUnit().toReceivedTimeMillis("1504230492763"));

// invalid
assertEquals(0L, ProxyHttpHeaderParser.NginxUnit.toReceivedTimeMillis("1504230492.76"));
assertEquals(0L, ProxyHttpHeaderParser.NginxUnit.toReceivedTimeMillis("1504230492.7"));
assertEquals(0L, ProxyHttpHeaderParser.NginxUnit.toReceivedTimeMillis("1504230492."));

assertEquals(0L, ProxyHttpHeaderParser.ApacheUnit.toReceivedTimeMillis("150"));
assertEquals(0L, ProxyHttpHeaderParser.ApacheUnit.toReceivedTimeMillis("15"));
assertEquals(0L, ProxyHttpHeaderParser.ApacheUnit.toReceivedTimeMillis("1"));
assertEquals(0L, ProxyHttpHeaderParser.ApacheUnit.toReceivedTimeMillis(""));
assertEquals(0L, ProxyHttpHeaderParser.ApacheUnit.toReceivedTimeMillis(null));

assertEquals(0L, ProxyHttpHeaderParser.AppUnit.toReceivedTimeMillis("A"));
assertEquals(0L, ProxyHttpHeaderParser.AppUnit.toReceivedTimeMillis("150B"));
assertEquals(0L, parser.getNginxUnit().toReceivedTimeMillis("1504230492.76"));
assertEquals(0L, parser.getNginxUnit().toReceivedTimeMillis("1504230492.7"));
assertEquals(0L, parser.getNginxUnit().toReceivedTimeMillis("1504230492."));

assertEquals(0L, parser.getApacheUnit().toReceivedTimeMillis("150"));
assertEquals(0L, parser.getApacheUnit().toReceivedTimeMillis("15"));
assertEquals(0L, parser.getApacheUnit().toReceivedTimeMillis("1"));
assertEquals(0L, parser.getApacheUnit().toReceivedTimeMillis(""));
assertEquals(0L, parser.getApacheUnit().toReceivedTimeMillis(null));

assertEquals(0L, parser.getAppUnit().toReceivedTimeMillis("A"));
assertEquals(0L, parser.getAppUnit().toReceivedTimeMillis("150B"));
}

@Test
public void toDurationTimeMicros() throws Exception {
ProxyHttpHeaderParser parser = new ProxyHttpHeaderParser();
assertEquals(1001000L, ProxyHttpHeaderParser.NginxUnit.toDurationTimeMicros("1.001"));
assertEquals(1000L, ProxyHttpHeaderParser.NginxUnit.toDurationTimeMicros("0.001"));
assertEquals(123L, ProxyHttpHeaderParser.ApacheUnit.toDurationTimeMicros("123"));
assertEquals(1001000, parser.getNginxUnit().toDurationTimeMicros("1.001"));
assertEquals(1000, parser.getNginxUnit().toDurationTimeMicros("0.001"));
assertEquals(123, parser.getApacheUnit().toDurationTimeMicros("123"));

// invalid
assertEquals(0L, ProxyHttpHeaderParser.NginxUnit.toDurationTimeMicros("1.01"));
assertEquals(0L, ProxyHttpHeaderParser.NginxUnit.toDurationTimeMicros("1.1"));
assertEquals(0L, ProxyHttpHeaderParser.NginxUnit.toDurationTimeMicros("1."));
assertEquals(0L, ProxyHttpHeaderParser.NginxUnit.toDurationTimeMicros(".0"));
assertEquals(0L, ProxyHttpHeaderParser.NginxUnit.toDurationTimeMicros(".01"));

assertEquals(0L, ProxyHttpHeaderParser.ApacheUnit.toDurationTimeMicros("a"));
assertEquals(0L, ProxyHttpHeaderParser.ApacheUnit.toDurationTimeMicros(""));
assertEquals(0L, ProxyHttpHeaderParser.ApacheUnit.toDurationTimeMicros(null));
assertEquals(0, parser.getNginxUnit().toDurationTimeMicros("1.01"));
assertEquals(0, parser.getNginxUnit().toDurationTimeMicros("1.1"));
assertEquals(0, parser.getNginxUnit().toDurationTimeMicros("1."));
assertEquals(0, parser.getNginxUnit().toDurationTimeMicros(".0"));
assertEquals(0, parser.getNginxUnit().toDurationTimeMicros(".01"));

assertEquals(0, parser.getApacheUnit().toDurationTimeMicros("a"));
assertEquals(0, parser.getApacheUnit().toDurationTimeMicros(""));
assertEquals(0, parser.getApacheUnit().toDurationTimeMicros(null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ String toDifferenceTimeFormat(final long proxyTimeMillis, final long startTimeMi
buffer.append(toMillis(absoluteDifference)).append("ms");
}

if (difference > 0) {
if (difference >= 0) {
buffer.append(" ago");
} else {
buffer.append(" from now");
Expand Down

0 comments on commit 694c4a8

Please sign in to comment.