mirror of
https://github.com/google/nomulus.git
synced 2025-05-15 08:57:12 +02:00
Record metrics for WHOIS commands
Note that this does not write out metrics for invocations of the nomulus tool. This requires a slight refactoring of the existing WhoisResponse interface so as to also support returning the number of results found by the WHOIS query. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=149461208
This commit is contained in:
parent
4eef02f17f
commit
3fcb564251
15 changed files with 247 additions and 62 deletions
|
@ -62,9 +62,9 @@ final class DomainWhoisResponse extends WhoisResponseImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPlainTextOutput(final boolean preferUnicode, String disclaimer) {
|
public WhoisResponseResults getResponse(final boolean preferUnicode, String disclaimer) {
|
||||||
Registrar registrar = getRegistrar(domain.getCurrentSponsorClientId());
|
Registrar registrar = getRegistrar(domain.getCurrentSponsorClientId());
|
||||||
return new DomainEmitter()
|
String plaintext = new DomainEmitter()
|
||||||
.emitField(
|
.emitField(
|
||||||
"Domain Name", maybeFormatHostname(domain.getFullyQualifiedDomainName(), preferUnicode))
|
"Domain Name", maybeFormatHostname(domain.getFullyQualifiedDomainName(), preferUnicode))
|
||||||
.emitField("Domain ID", domain.getRepoId())
|
.emitField("Domain ID", domain.getRepoId())
|
||||||
|
@ -97,6 +97,7 @@ final class DomainWhoisResponse extends WhoisResponseImpl {
|
||||||
.emitAwipMessage()
|
.emitAwipMessage()
|
||||||
.emitFooter(disclaimer)
|
.emitFooter(disclaimer)
|
||||||
.toString();
|
.toString();
|
||||||
|
return WhoisResponseResults.create(plaintext, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the contact of the given type, or null if it does not exist. */
|
/** Returns the contact of the given type, or null if it does not exist. */
|
||||||
|
|
|
@ -42,7 +42,7 @@ final class NameserverWhoisResponse extends WhoisResponseImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPlainTextOutput(boolean preferUnicode, String disclaimer) {
|
public WhoisResponseResults getResponse(boolean preferUnicode, String disclaimer) {
|
||||||
BasicEmitter emitter = new BasicEmitter();
|
BasicEmitter emitter = new BasicEmitter();
|
||||||
for (int i = 0; i < hosts.size(); i++) {
|
for (int i = 0; i < hosts.size(); i++) {
|
||||||
HostResource host = hosts.get(i);
|
HostResource host = hosts.get(i);
|
||||||
|
@ -63,6 +63,7 @@ final class NameserverWhoisResponse extends WhoisResponseImpl {
|
||||||
emitter.emitNewline();
|
emitter.emitNewline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return emitter.emitLastUpdated(getTimestamp()).emitFooter(disclaimer).toString();
|
String plaintext = emitter.emitLastUpdated(getTimestamp()).emitFooter(disclaimer).toString();
|
||||||
|
return WhoisResponseResults.create(plaintext, hosts.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,9 @@ class RegistrarWhoisResponse extends WhoisResponseImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPlainTextOutput(boolean preferUnicode, String disclaimer) {
|
public WhoisResponseResults getResponse(boolean preferUnicode, String disclaimer) {
|
||||||
Set<RegistrarContact> contacts = registrar.getContacts();
|
Set<RegistrarContact> contacts = registrar.getContacts();
|
||||||
return new RegistrarEmitter()
|
String plaintext = new RegistrarEmitter()
|
||||||
.emitField("Registrar Name", registrar.getRegistrarName())
|
.emitField("Registrar Name", registrar.getRegistrarName())
|
||||||
.emitAddress(
|
.emitAddress(
|
||||||
null,
|
null,
|
||||||
|
@ -62,6 +62,7 @@ class RegistrarWhoisResponse extends WhoisResponseImpl {
|
||||||
.emitLastUpdated(getTimestamp())
|
.emitLastUpdated(getTimestamp())
|
||||||
.emitFooter(disclaimer)
|
.emitFooter(disclaimer)
|
||||||
.toString();
|
.toString();
|
||||||
|
return WhoisResponseResults.create(plaintext, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An emitter with logic for registrars. */
|
/** An emitter with logic for registrars. */
|
||||||
|
|
|
@ -46,9 +46,10 @@ public final class Whois {
|
||||||
.create(now)
|
.create(now)
|
||||||
.readCommand(new StringReader(query))
|
.readCommand(new StringReader(query))
|
||||||
.executeQuery(now)
|
.executeQuery(now)
|
||||||
.getPlainTextOutput(preferUnicode, disclaimer);
|
.getResponse(preferUnicode, disclaimer)
|
||||||
|
.plainTextOutput();
|
||||||
} catch (WhoisException e) {
|
} catch (WhoisException e) {
|
||||||
return e.getPlainTextOutput(preferUnicode, disclaimer);
|
return e.getResponse(preferUnicode, disclaimer).plainTextOutput();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,11 +60,12 @@ public final class WhoisException extends Exception implements WhoisResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPlainTextOutput(boolean preferUnicode, String disclaimer) {
|
public WhoisResponseResults getResponse(boolean preferUnicode, String disclaimer) {
|
||||||
return new WhoisResponseImpl.BasicEmitter()
|
String plaintext = new WhoisResponseImpl.BasicEmitter()
|
||||||
.emitRawLine(getMessage())
|
.emitRawLine(getMessage())
|
||||||
.emitLastUpdated(getTimestamp())
|
.emitLastUpdated(getTimestamp())
|
||||||
.emitFooter(disclaimer)
|
.emitFooter(disclaimer)
|
||||||
.toString();
|
.toString();
|
||||||
|
return WhoisResponseResults.create(plaintext, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static com.google.common.net.HttpHeaders.LAST_MODIFIED;
|
||||||
import static com.google.common.net.HttpHeaders.X_CONTENT_TYPE_OPTIONS;
|
import static com.google.common.net.HttpHeaders.X_CONTENT_TYPE_OPTIONS;
|
||||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
@ -33,6 +34,8 @@ import google.registry.request.RequestPath;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import google.registry.util.FormattingLogger;
|
import google.registry.util.FormattingLogger;
|
||||||
|
import google.registry.whois.WhoisMetrics.WhoisMetric;
|
||||||
|
import google.registry.whois.WhoisResponse.WhoisResponseResults;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
@ -133,6 +136,8 @@ public final class WhoisHttpServer implements Runnable {
|
||||||
@Inject @Config("whoisHttpExpires") Duration expires;
|
@Inject @Config("whoisHttpExpires") Duration expires;
|
||||||
@Inject WhoisReaderFactory whoisReaderFactory;
|
@Inject WhoisReaderFactory whoisReaderFactory;
|
||||||
@Inject @RequestPath String requestPath;
|
@Inject @RequestPath String requestPath;
|
||||||
|
@Inject WhoisMetric.Builder metricBuilder;
|
||||||
|
@Inject WhoisMetrics whoisMetrics;
|
||||||
@Inject WhoisHttpServer() {}
|
@Inject WhoisHttpServer() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -141,27 +146,38 @@ public final class WhoisHttpServer implements Runnable {
|
||||||
String path = nullToEmpty(requestPath);
|
String path = nullToEmpty(requestPath);
|
||||||
try {
|
try {
|
||||||
// Extremely permissive parsing that turns stuff like "/hello/world/" into "hello world".
|
// Extremely permissive parsing that turns stuff like "/hello/world/" into "hello world".
|
||||||
String command = decode(JOINER.join(SLASHER.split(path.substring(PATH.length())))) + "\r\n";
|
String commandText =
|
||||||
|
decode(JOINER.join(SLASHER.split(path.substring(PATH.length())))) + "\r\n";
|
||||||
DateTime now = clock.nowUtc();
|
DateTime now = clock.nowUtc();
|
||||||
sendResponse(
|
WhoisCommand command =
|
||||||
SC_OK,
|
whoisReaderFactory.create(now).readCommand(new StringReader(commandText));
|
||||||
whoisReaderFactory.create(now).readCommand(new StringReader(command)).executeQuery(now));
|
metricBuilder.setCommand(command);
|
||||||
|
sendResponse(SC_OK, command.executeQuery(now));
|
||||||
} catch (WhoisException e) {
|
} catch (WhoisException e) {
|
||||||
|
metricBuilder.setStatus(e.getStatus());
|
||||||
|
metricBuilder.setNumResults(0);
|
||||||
sendResponse(e.getStatus(), e);
|
sendResponse(e.getStatus(), e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
metricBuilder.setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||||
|
metricBuilder.setNumResults(0);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
whoisMetrics.recordWhoisMetric(metricBuilder.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendResponse(int status, WhoisResponse whoisResponse) {
|
private void sendResponse(int status, WhoisResponse whoisResponse) {
|
||||||
response.setStatus(status);
|
response.setStatus(status);
|
||||||
|
metricBuilder.setStatus(status);
|
||||||
response.setDateHeader(LAST_MODIFIED, whoisResponse.getTimestamp());
|
response.setDateHeader(LAST_MODIFIED, whoisResponse.getTimestamp());
|
||||||
response.setDateHeader(EXPIRES, whoisResponse.getTimestamp().plus(expires));
|
response.setDateHeader(EXPIRES, whoisResponse.getTimestamp().plus(expires));
|
||||||
response.setHeader(CACHE_CONTROL, CACHE_CONTROL_VALUE);
|
response.setHeader(CACHE_CONTROL, CACHE_CONTROL_VALUE);
|
||||||
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN, CORS_ALLOW_ORIGIN);
|
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN, CORS_ALLOW_ORIGIN);
|
||||||
response.setHeader(X_CONTENT_TYPE_OPTIONS, X_CONTENT_NO_SNIFF);
|
response.setHeader(X_CONTENT_TYPE_OPTIONS, X_CONTENT_NO_SNIFF);
|
||||||
response.setContentType(PLAIN_TEXT_UTF_8);
|
response.setContentType(PLAIN_TEXT_UTF_8);
|
||||||
response.setPayload(whoisResponse.getPlainTextOutput(true, disclaimer));
|
WhoisResponseResults results = whoisResponse.getResponse(true, disclaimer);
|
||||||
|
metricBuilder.setNumResults(results.numResults());
|
||||||
|
response.setPayload(results.plainTextOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Removes {@code %xx} escape codes from request path components. */
|
/** Removes {@code %xx} escape codes from request path components. */
|
||||||
|
|
|
@ -14,15 +14,18 @@
|
||||||
|
|
||||||
package google.registry.whois;
|
package google.registry.whois;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
import static google.registry.monitoring.metrics.EventMetric.DEFAULT_FITTER;
|
import static google.registry.monitoring.metrics.EventMetric.DEFAULT_FITTER;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import google.registry.monitoring.metrics.EventMetric;
|
import google.registry.monitoring.metrics.EventMetric;
|
||||||
import google.registry.monitoring.metrics.IncrementableMetric;
|
import google.registry.monitoring.metrics.IncrementableMetric;
|
||||||
import google.registry.monitoring.metrics.LabelDescriptor;
|
import google.registry.monitoring.metrics.LabelDescriptor;
|
||||||
import google.registry.monitoring.metrics.MetricRegistryImpl;
|
import google.registry.monitoring.metrics.MetricRegistryImpl;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
|
import google.registry.whois.WhoisMetrics.WhoisMetric;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
@ -57,36 +60,28 @@ public class WhoisMetrics {
|
||||||
@Inject
|
@Inject
|
||||||
public WhoisMetrics() {}
|
public WhoisMetrics() {}
|
||||||
|
|
||||||
/**
|
/** Records the given {@link WhoisMetric} and its associated processing time. */
|
||||||
* Increment a counter which tracks WHOIS requests.
|
public void recordWhoisMetric(WhoisMetric metric) {
|
||||||
*
|
|
||||||
* @see WhoisServer
|
|
||||||
*/
|
|
||||||
public void incrementWhoisRequests(WhoisMetric metric) {
|
|
||||||
whoisRequests.increment(
|
whoisRequests.increment(
|
||||||
metric.commandName(),
|
metric.commandName().or(""),
|
||||||
metric.numResults().toString(),
|
Integer.toString(metric.numResults()),
|
||||||
metric.status());
|
Integer.toString(metric.status()));
|
||||||
}
|
|
||||||
|
|
||||||
/** Record the server-side processing time for a WHOIS request. */
|
|
||||||
public void recordProcessingTime(WhoisMetric metric) {
|
|
||||||
processingTime.record(
|
processingTime.record(
|
||||||
metric.endTimestamp().getMillis() - metric.startTimestamp().getMillis(),
|
metric.endTimestamp().getMillis() - metric.startTimestamp().getMillis(),
|
||||||
metric.commandName(),
|
metric.commandName().or(""),
|
||||||
metric.numResults().toString(),
|
Integer.toString(metric.numResults()),
|
||||||
metric.status());
|
Integer.toString(metric.status()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A value class for recording attributes of a WHOIS metric. */
|
/** A value class for recording attributes of a WHOIS metric. */
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract static class WhoisMetric {
|
public abstract static class WhoisMetric {
|
||||||
|
|
||||||
public abstract String commandName();
|
public abstract Optional<String> commandName();
|
||||||
|
|
||||||
public abstract Integer numResults();
|
public abstract int numResults();
|
||||||
|
|
||||||
public abstract String status();
|
public abstract int status();
|
||||||
|
|
||||||
public abstract DateTime startTimestamp();
|
public abstract DateTime startTimestamp();
|
||||||
|
|
||||||
|
@ -111,14 +106,20 @@ public class WhoisMetrics {
|
||||||
@AutoValue.Builder
|
@AutoValue.Builder
|
||||||
public abstract static class Builder {
|
public abstract static class Builder {
|
||||||
|
|
||||||
|
boolean wasBuilt = false;
|
||||||
|
|
||||||
/** Builder-only clock to support automatic recording of endTimestamp on {@link #build()}. */
|
/** Builder-only clock to support automatic recording of endTimestamp on {@link #build()}. */
|
||||||
private Clock clock = null;
|
private Clock clock = null;
|
||||||
|
|
||||||
|
public Builder setCommand(WhoisCommand command) {
|
||||||
|
return setCommandName(command.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
public abstract Builder setCommandName(String commandName);
|
public abstract Builder setCommandName(String commandName);
|
||||||
|
|
||||||
public abstract Builder setNumResults(Integer numResults);
|
public abstract Builder setNumResults(int numResults);
|
||||||
|
|
||||||
public abstract Builder setStatus(String status);
|
public abstract Builder setStatus(int status);
|
||||||
|
|
||||||
abstract Builder setStartTimestamp(DateTime startTimestamp);
|
abstract Builder setStartTimestamp(DateTime startTimestamp);
|
||||||
|
|
||||||
|
@ -136,9 +137,12 @@ public class WhoisMetrics {
|
||||||
* current timestamp of the clock; otherwise end timestamp must have been previously set.
|
* current timestamp of the clock; otherwise end timestamp must have been previously set.
|
||||||
*/
|
*/
|
||||||
public WhoisMetric build() {
|
public WhoisMetric build() {
|
||||||
|
checkState(
|
||||||
|
!wasBuilt, "WhoisMetric was already built; building it again is most likely an error");
|
||||||
if (clock != null) {
|
if (clock != null) {
|
||||||
setEndTimestamp(clock.nowUtc());
|
setEndTimestamp(clock.nowUtc());
|
||||||
}
|
}
|
||||||
|
wasBuilt = true;
|
||||||
return autoBuild();
|
return autoBuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ import org.joda.time.DateTime;
|
||||||
* @see <a href="http://tools.ietf.org/html/rfc3912">RFC 3912</a>
|
* @see <a href="http://tools.ietf.org/html/rfc3912">RFC 3912</a>
|
||||||
* @see <a href="http://www.iana.org/assignments/registrar-ids">IANA Registrar IDs</a>
|
* @see <a href="http://www.iana.org/assignments/registrar-ids">IANA Registrar IDs</a>
|
||||||
*/
|
*/
|
||||||
@AutoFactory
|
@AutoFactory(allowSubclasses = true)
|
||||||
class WhoisReader {
|
class WhoisReader {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,13 +14,14 @@
|
||||||
|
|
||||||
package google.registry.whois;
|
package google.registry.whois;
|
||||||
|
|
||||||
|
import com.google.auto.value.AutoValue;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
/** Representation of a WHOIS query response. */
|
/** Representation of a WHOIS query response. */
|
||||||
public interface WhoisResponse {
|
public interface WhoisResponse {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a plain text WHOIS response.
|
* Returns the WHOIS response.
|
||||||
*
|
*
|
||||||
* @param preferUnicode if {@code false} will cause the output to be converted to ASCII whenever
|
* @param preferUnicode if {@code false} will cause the output to be converted to ASCII whenever
|
||||||
* possible; for example, converting IDN hostname labels to punycode. However certain things
|
* possible; for example, converting IDN hostname labels to punycode. However certain things
|
||||||
|
@ -29,10 +30,19 @@ public interface WhoisResponse {
|
||||||
* be set to {@code true}.
|
* be set to {@code true}.
|
||||||
* @param disclaimer text to show at bottom of output
|
* @param disclaimer text to show at bottom of output
|
||||||
*/
|
*/
|
||||||
String getPlainTextOutput(boolean preferUnicode, String disclaimer);
|
WhoisResponseResults getResponse(boolean preferUnicode, String disclaimer);
|
||||||
|
|
||||||
/**
|
/** Returns the time at which this response was created. */
|
||||||
* Returns the time at which this response was created.
|
|
||||||
*/
|
|
||||||
DateTime getTimestamp();
|
DateTime getTimestamp();
|
||||||
|
|
||||||
|
/** A wraper class for the plaintext response of a WHOIS command and its number of results. */
|
||||||
|
@AutoValue
|
||||||
|
abstract static class WhoisResponseResults {
|
||||||
|
public abstract String plainTextOutput();
|
||||||
|
public abstract int numResults();
|
||||||
|
|
||||||
|
static WhoisResponseResults create(String plainTextOutput, int numResults) {
|
||||||
|
return new AutoValue_WhoisResponse_WhoisResponseResults(plainTextOutput, numResults);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package google.registry.whois;
|
package google.registry.whois;
|
||||||
|
|
||||||
import static google.registry.request.Action.Method.POST;
|
import static google.registry.request.Action.Method.POST;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
import com.google.common.net.MediaType;
|
import com.google.common.net.MediaType;
|
||||||
|
@ -23,6 +24,8 @@ import google.registry.request.Action;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import google.registry.util.FormattingLogger;
|
import google.registry.util.FormattingLogger;
|
||||||
|
import google.registry.whois.WhoisMetrics.WhoisMetric;
|
||||||
|
import google.registry.whois.WhoisResponse.WhoisResponseResults;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
@ -60,6 +63,8 @@ public class WhoisServer implements Runnable {
|
||||||
@Inject Response response;
|
@Inject Response response;
|
||||||
@Inject WhoisReaderFactory whoisReaderFactory;
|
@Inject WhoisReaderFactory whoisReaderFactory;
|
||||||
@Inject @Config("whoisDisclaimer") String disclaimer;
|
@Inject @Config("whoisDisclaimer") String disclaimer;
|
||||||
|
@Inject WhoisMetric.Builder metricBuilder;
|
||||||
|
@Inject WhoisMetrics whoisMetrics;
|
||||||
@Inject WhoisServer() {}
|
@Inject WhoisServer() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -67,17 +72,23 @@ public class WhoisServer implements Runnable {
|
||||||
String responseText;
|
String responseText;
|
||||||
DateTime now = clock.nowUtc();
|
DateTime now = clock.nowUtc();
|
||||||
try {
|
try {
|
||||||
responseText =
|
WhoisCommand command = whoisReaderFactory.create(now).readCommand(input);
|
||||||
whoisReaderFactory
|
metricBuilder.setCommand(command);
|
||||||
.create(now)
|
WhoisResponseResults results =
|
||||||
.readCommand(input)
|
command.executeQuery(now).getResponse(PREFER_UNICODE, disclaimer);
|
||||||
.executeQuery(now)
|
responseText = results.plainTextOutput();
|
||||||
.getPlainTextOutput(PREFER_UNICODE, disclaimer);
|
metricBuilder.setNumResults(results.numResults());
|
||||||
|
metricBuilder.setStatus(SC_OK);
|
||||||
} catch (WhoisException e) {
|
} catch (WhoisException e) {
|
||||||
responseText = e.getPlainTextOutput(PREFER_UNICODE, disclaimer);
|
WhoisResponseResults results = e.getResponse(PREFER_UNICODE, disclaimer);
|
||||||
|
responseText = results.plainTextOutput();
|
||||||
|
metricBuilder.setNumResults(0);
|
||||||
|
metricBuilder.setStatus(e.getStatus());
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.severe(t, "WHOIS request crashed");
|
logger.severe(t, "WHOIS request crashed");
|
||||||
responseText = "Internal Server Error";
|
responseText = "Internal Server Error";
|
||||||
|
metricBuilder.setNumResults(0);
|
||||||
|
metricBuilder.setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
// Note that we always return 200 (OK) even if an error was hit. This is because returning an
|
// Note that we always return 200 (OK) even if an error was hit. This is because returning an
|
||||||
// non-OK HTTP status code will cause the proxy server to silently close the connection. Since
|
// non-OK HTTP status code will cause the proxy server to silently close the connection. Since
|
||||||
|
@ -86,5 +97,6 @@ public class WhoisServer implements Runnable {
|
||||||
response.setStatus(SC_OK);
|
response.setStatus(SC_OK);
|
||||||
response.setContentType(CONTENT_TYPE);
|
response.setContentType(CONTENT_TYPE);
|
||||||
response.setPayload(responseText);
|
response.setPayload(responseText);
|
||||||
|
whoisMetrics.recordWhoisMetric(metricBuilder.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import google.registry.model.host.HostResource;
|
||||||
import google.registry.model.registrar.Registrar;
|
import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
|
import google.registry.whois.WhoisResponse.WhoisResponseResults;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
@ -239,16 +240,16 @@ public class DomainWhoisResponseTest {
|
||||||
public void getPlainTextOutputTest() {
|
public void getPlainTextOutputTest() {
|
||||||
DomainWhoisResponse domainWhoisResponse =
|
DomainWhoisResponse domainWhoisResponse =
|
||||||
new DomainWhoisResponse(domainResource, clock.nowUtc());
|
new DomainWhoisResponse(domainResource, clock.nowUtc());
|
||||||
assertThat(domainWhoisResponse.getPlainTextOutput(false, "Doodle Disclaimer"))
|
assertThat(domainWhoisResponse.getResponse(false, "Doodle Disclaimer"))
|
||||||
.isEqualTo(loadWhoisTestFile("whois_domain.txt"));
|
.isEqualTo(WhoisResponseResults.create(loadWhoisTestFile("whois_domain.txt"), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addImplicitOkStatusTest() {
|
public void addImplicitOkStatusTest() {
|
||||||
DomainWhoisResponse domainWhoisResponse = new DomainWhoisResponse(
|
DomainWhoisResponse domainWhoisResponse =
|
||||||
domainResource.asBuilder().setStatusValues(null).build(),
|
new DomainWhoisResponse(
|
||||||
clock.nowUtc());
|
domainResource.asBuilder().setStatusValues(null).build(), clock.nowUtc());
|
||||||
assertThat(domainWhoisResponse.getPlainTextOutput(false, "Doodle Disclaimer"))
|
assertThat(domainWhoisResponse.getResponse(false, "Doodle Disclaimer").plainTextOutput())
|
||||||
.contains("Domain Status: ok");
|
.contains("Domain Status: ok");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import google.registry.model.host.HostResource;
|
||||||
import google.registry.model.registrar.Registrar;
|
import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
|
import google.registry.whois.WhoisResponse.WhoisResponseResults;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
@ -81,15 +82,16 @@ public class NameserverWhoisResponseTest {
|
||||||
public void testGetTextOutput() {
|
public void testGetTextOutput() {
|
||||||
NameserverWhoisResponse nameserverWhoisResponse =
|
NameserverWhoisResponse nameserverWhoisResponse =
|
||||||
new NameserverWhoisResponse(hostResource1, clock.nowUtc());
|
new NameserverWhoisResponse(hostResource1, clock.nowUtc());
|
||||||
assertThat(nameserverWhoisResponse.getPlainTextOutput(false, "Doodle Disclaimer"))
|
assertThat(nameserverWhoisResponse.getResponse(false, "Doodle Disclaimer"))
|
||||||
.isEqualTo(loadWhoisTestFile("whois_nameserver.txt"));
|
.isEqualTo(WhoisResponseResults.create(loadWhoisTestFile("whois_nameserver.txt"), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetMultipleNameserversResponse() {
|
public void testGetMultipleNameserversResponse() {
|
||||||
NameserverWhoisResponse nameserverWhoisResponse =
|
NameserverWhoisResponse nameserverWhoisResponse =
|
||||||
new NameserverWhoisResponse(ImmutableList.of(hostResource1, hostResource2), clock.nowUtc());
|
new NameserverWhoisResponse(ImmutableList.of(hostResource1, hostResource2), clock.nowUtc());
|
||||||
assertThat(nameserverWhoisResponse.getPlainTextOutput(false, "Doodle Disclaimer"))
|
assertThat(nameserverWhoisResponse.getResponse(false, "Doodle Disclaimer"))
|
||||||
.isEqualTo(loadWhoisTestFile("whois_multiple_nameservers.txt"));
|
.isEqualTo(
|
||||||
|
WhoisResponseResults.create(loadWhoisTestFile("whois_multiple_nameservers.txt"), 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import google.registry.model.registrar.RegistrarAddress;
|
||||||
import google.registry.model.registrar.RegistrarContact;
|
import google.registry.model.registrar.RegistrarContact;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
|
import google.registry.whois.WhoisResponse.WhoisResponseResults;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -113,8 +114,8 @@ public class RegistrarWhoisResponseTest {
|
||||||
|
|
||||||
RegistrarWhoisResponse registrarWhoisResponse =
|
RegistrarWhoisResponse registrarWhoisResponse =
|
||||||
new RegistrarWhoisResponse(registrar, clock.nowUtc());
|
new RegistrarWhoisResponse(registrar, clock.nowUtc());
|
||||||
assertThat(registrarWhoisResponse.getPlainTextOutput(false, "Doodle Disclaimer"))
|
assertThat(registrarWhoisResponse.getResponse(false, "Doodle Disclaimer"))
|
||||||
.isEqualTo(loadWhoisTestFile("whois_registrar.txt"));
|
.isEqualTo(WhoisResponseResults.create(loadWhoisTestFile("whois_registrar.txt"), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -129,6 +130,6 @@ public class RegistrarWhoisResponseTest {
|
||||||
RegistrarWhoisResponse registrarWhoisResponse =
|
RegistrarWhoisResponse registrarWhoisResponse =
|
||||||
new RegistrarWhoisResponse(registrar, clock.nowUtc());
|
new RegistrarWhoisResponse(registrar, clock.nowUtc());
|
||||||
// Just make sure this doesn't NPE.
|
// Just make sure this doesn't NPE.
|
||||||
registrarWhoisResponse.getPlainTextOutput(false, "Doodle Disclaimer");
|
registrarWhoisResponse.getResponse(false, "Doodle Disclaimer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ package google.registry.whois;
|
||||||
|
|
||||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.common.truth.Truth.assert_;
|
||||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||||
import static google.registry.testing.DatastoreHelper.persistSimpleResources;
|
import static google.registry.testing.DatastoreHelper.persistSimpleResources;
|
||||||
|
@ -25,6 +26,14 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeHostResourc
|
||||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
||||||
import static google.registry.whois.WhoisHelper.loadWhoisTestFile;
|
import static google.registry.whois.WhoisHelper.loadWhoisTestFile;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import google.registry.model.contact.ContactResource;
|
import google.registry.model.contact.ContactResource;
|
||||||
import google.registry.model.ofy.Ofy;
|
import google.registry.model.ofy.Ofy;
|
||||||
|
@ -35,6 +44,9 @@ import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.testing.Providers;
|
import google.registry.testing.Providers;
|
||||||
|
import google.registry.whois.WhoisMetrics.WhoisMetric;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -68,6 +80,8 @@ public class WhoisHttpServerTest {
|
||||||
whoisServer.response = response;
|
whoisServer.response = response;
|
||||||
whoisServer.whoisReaderFactory =
|
whoisServer.whoisReaderFactory =
|
||||||
new WhoisReaderFactory(Providers.of(new WhoisCommandFactory()));
|
new WhoisReaderFactory(Providers.of(new WhoisCommandFactory()));
|
||||||
|
whoisServer.whoisMetrics = new WhoisMetrics();
|
||||||
|
whoisServer.metricBuilder = WhoisMetric.builderForRequest(clock);
|
||||||
whoisServer.disclaimer = "Doodle Disclaimer";
|
whoisServer.disclaimer = "Doodle Disclaimer";
|
||||||
return whoisServer;
|
return whoisServer;
|
||||||
}
|
}
|
||||||
|
@ -331,4 +345,57 @@ public class WhoisHttpServerTest {
|
||||||
assertThat(response.getPayload())
|
assertThat(response.getPayload())
|
||||||
.isEqualTo(loadWhoisTestFile("whois_server_registrar_not_found.txt"));
|
.isEqualTo(loadWhoisTestFile("whois_server_registrar_not_found.txt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRun_metricsLoggedForSuccessfulCommand() throws Exception {
|
||||||
|
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
|
||||||
|
WhoisHttpServer server = newWhoisHttpServer("/nameserver/ns1.cat.lol");
|
||||||
|
server.whoisMetrics = mock(WhoisMetrics.class);
|
||||||
|
server.run();
|
||||||
|
WhoisMetric expected =
|
||||||
|
WhoisMetric.builderForRequest(clock)
|
||||||
|
.setCommandName("NameserverLookupByHostCommand")
|
||||||
|
.setNumResults(1)
|
||||||
|
.setStatus(SC_OK)
|
||||||
|
.build();
|
||||||
|
verify(server.whoisMetrics).recordWhoisMetric(eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRun_metricsLoggedForUnsuccessfulCommand() throws Exception {
|
||||||
|
WhoisHttpServer server = newWhoisHttpServer("nic.%u307F%u3093%u306A");
|
||||||
|
server.whoisMetrics = mock(WhoisMetrics.class);
|
||||||
|
server.run();
|
||||||
|
WhoisMetric expected =
|
||||||
|
WhoisMetric.builderForRequest(clock).setNumResults(0).setStatus(SC_BAD_REQUEST).build();
|
||||||
|
verify(server.whoisMetrics).recordWhoisMetric(eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRun_metricsLoggedForInternalServerError() throws Exception {
|
||||||
|
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
|
||||||
|
WhoisHttpServer server = newWhoisHttpServer("ns1.cat.lol");
|
||||||
|
final WhoisReader reader = mock(WhoisReader.class);
|
||||||
|
when(reader.readCommand(any(Reader.class))).thenThrow(new IOException("missing cat interface"));
|
||||||
|
|
||||||
|
server.whoisReaderFactory = new WhoisReaderFactory(Providers.of(new WhoisCommandFactory())) {
|
||||||
|
@Override
|
||||||
|
WhoisReader create(DateTime now) {
|
||||||
|
return reader;
|
||||||
|
}};
|
||||||
|
server.whoisMetrics = mock(WhoisMetrics.class);
|
||||||
|
|
||||||
|
try {
|
||||||
|
server.run();
|
||||||
|
assert_().fail("Should have thrown RuntimeException");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
assertThat(e.getCause().getMessage()).isEqualTo("missing cat interface");
|
||||||
|
}
|
||||||
|
WhoisMetric expected =
|
||||||
|
WhoisMetric.builderForRequest(clock)
|
||||||
|
.setNumResults(0)
|
||||||
|
.setStatus(SC_INTERNAL_SERVER_ERROR)
|
||||||
|
.build();
|
||||||
|
verify(server.whoisMetrics).recordWhoisMetric(eq(expected));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,14 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeHostResourc
|
||||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
||||||
import static google.registry.whois.WhoisHelper.loadWhoisTestFile;
|
import static google.registry.whois.WhoisHelper.loadWhoisTestFile;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import google.registry.model.domain.DomainResource;
|
import google.registry.model.domain.DomainResource;
|
||||||
import google.registry.model.ofy.Ofy;
|
import google.registry.model.ofy.Ofy;
|
||||||
|
@ -37,6 +45,9 @@ import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.testing.Providers;
|
import google.registry.testing.Providers;
|
||||||
|
import google.registry.whois.WhoisMetrics.WhoisMetric;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -63,6 +74,8 @@ public class WhoisServerTest {
|
||||||
whoisServer.response = response;
|
whoisServer.response = response;
|
||||||
whoisServer.whoisReaderFactory =
|
whoisServer.whoisReaderFactory =
|
||||||
new WhoisReaderFactory(Providers.of(new WhoisCommandFactory()));
|
new WhoisReaderFactory(Providers.of(new WhoisCommandFactory()));
|
||||||
|
whoisServer.whoisMetrics = new WhoisMetrics();
|
||||||
|
whoisServer.metricBuilder = WhoisMetric.builderForRequest(clock);
|
||||||
whoisServer.disclaimer = "Doodle Disclaimer";
|
whoisServer.disclaimer = "Doodle Disclaimer";
|
||||||
return whoisServer;
|
return whoisServer;
|
||||||
}
|
}
|
||||||
|
@ -430,4 +443,58 @@ public class WhoisServerTest {
|
||||||
assertThat(response.getPayload()).contains("ns1.cat.1.test");
|
assertThat(response.getPayload()).contains("ns1.cat.1.test");
|
||||||
assertThat(response.getPayload()).contains("1.2.3.4");
|
assertThat(response.getPayload()).contains("1.2.3.4");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRun_metricsLoggedForSuccessfulCommand() throws Exception {
|
||||||
|
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
|
||||||
|
persistResource(makeHostResource("ns2.cat.lol", "1.2.3.4"));
|
||||||
|
WhoisServer server = newWhoisServer("nameserver 1.2.3.4");
|
||||||
|
server.whoisMetrics = mock(WhoisMetrics.class);
|
||||||
|
server.run();
|
||||||
|
WhoisMetric expected =
|
||||||
|
WhoisMetric.builderForRequest(clock)
|
||||||
|
.setCommandName("NameserverLookupByIpCommand")
|
||||||
|
.setNumResults(2)
|
||||||
|
.setStatus(SC_OK)
|
||||||
|
.build();
|
||||||
|
verify(server.whoisMetrics).recordWhoisMetric(eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRun_metricsLoggedForUnsuccessfulCommand() throws Exception {
|
||||||
|
WhoisServer server = newWhoisServer("domain cat.lol\r\n");
|
||||||
|
server.whoisMetrics = mock(WhoisMetrics.class);
|
||||||
|
server.run();
|
||||||
|
WhoisMetric expected =
|
||||||
|
WhoisMetric.builderForRequest(clock)
|
||||||
|
.setCommandName("DomainLookupCommand")
|
||||||
|
.setNumResults(0)
|
||||||
|
.setStatus(SC_NOT_FOUND)
|
||||||
|
.build();
|
||||||
|
verify(server.whoisMetrics).recordWhoisMetric(eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRun_metricsLoggedForInternalServerError() throws Exception {
|
||||||
|
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
|
||||||
|
WhoisServer server = newWhoisServer("ns1.cat.lol");
|
||||||
|
final WhoisReader reader = mock(WhoisReader.class);
|
||||||
|
when(reader.readCommand(any(Reader.class))).thenThrow(new IOException("missing cat interface"));
|
||||||
|
|
||||||
|
server.whoisReaderFactory = new WhoisReaderFactory(Providers.of(new WhoisCommandFactory())) {
|
||||||
|
@Override
|
||||||
|
WhoisReader create(DateTime now) {
|
||||||
|
return reader;
|
||||||
|
}};
|
||||||
|
server.whoisMetrics = mock(WhoisMetrics.class);
|
||||||
|
|
||||||
|
server.run();
|
||||||
|
WhoisMetric expected =
|
||||||
|
WhoisMetric.builderForRequest(clock)
|
||||||
|
.setNumResults(0)
|
||||||
|
.setStatus(SC_INTERNAL_SERVER_ERROR)
|
||||||
|
.build();
|
||||||
|
verify(server.whoisMetrics).recordWhoisMetric(eq(expected));
|
||||||
|
assertThat(response.getPayload()).isEqualTo("Internal Server Error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue