aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mitmproxy/web/app.py50
-rw-r--r--web/src/css/app.less1
-rw-r--r--web/src/css/contentview.less10
-rw-r--r--web/src/js/components/ContentView.jsx2
-rw-r--r--web/src/js/components/ContentView/ContentLoader.jsx2
-rw-r--r--web/src/js/components/ContentView/ContentViews.jsx42
-rw-r--r--web/src/js/components/ContentView/ViewSelector.jsx2
-rw-r--r--web/src/js/flow/utils.js4
8 files changed, 81 insertions, 32 deletions
diff --git a/mitmproxy/web/app.py b/mitmproxy/web/app.py
index 5f756ed1..6abd672d 100644
--- a/mitmproxy/web/app.py
+++ b/mitmproxy/web/app.py
@@ -14,6 +14,7 @@ import tornado.web
from io import BytesIO
from mitmproxy.flow import FlowWriter, FlowReader
+from mitmproxy import exceptions
from mitmproxy import filt
from mitmproxy import models
from mitmproxy import contentviews
@@ -305,6 +306,36 @@ class ReplayFlow(RequestHandler):
class FlowContent(RequestHandler):
+ def _get_content_view(self, message, viewmode):
+
+ try:
+ content = message.content
+ if content != message.raw_content:
+ enc = "[decoded {}]".format(
+ message.headers.get("content-encoding")
+ )
+ else:
+ enc = None
+ except ValueError:
+ content = message.raw_content
+ enc = "[cannot decode]"
+ try:
+ query = None
+ if isinstance(message, models.HTTPRequest):
+ query = message.query
+ description, lines = contentviews.get_content_view(
+ viewmode, content, headers=message.headers, query=query
+ )
+ except exceptions.ContentViewException:
+ description, lines = contentviews.get_content_view(
+ contentviews.get("Raw"), content, headers=message.headers
+ )
+ description = description.replace("Raw", "Couldn't parse: falling back to Raw")
+
+ if enc:
+ description = " ".join([enc, description])
+
+ return description, lines
def post(self, flow_id, message):
self.flow.backup()
@@ -314,7 +345,6 @@ class FlowContent(RequestHandler):
def get(self, flow_id, message):
message = getattr(self.flow, message)
- contentview = self.get_argument("content_view", "raw", True)
if not message.raw_content:
raise APIError(400, "No content.")
@@ -339,7 +369,21 @@ class FlowContent(RequestHandler):
self.set_header("Content-Type", "application/text")
self.set_header("X-Content-Type-Options", "nosniff")
self.set_header("X-Frame-Options", "DENY")
- self.write(message.raw_content)
+
+ cv = self.get_argument("cv", None)
+ if cv:
+ self.set_header("Content-Encoding", "")
+ viewmode = next(v for v in contentviews.views if v.name == cv)
+ description, lines = self._get_content_view(
+ message, viewmode
+ )
+
+ self.write(dict(
+ lines=list(lines),
+ description=description
+ ))
+ else:
+ self.write(message.raw_content)
class Events(RequestHandler):
@@ -368,7 +412,7 @@ class Settings(RequestHandler):
stickyauth=self.master.options.stickyauth,
stickycookie=self.master.options.stickycookie,
stream= self.master.options.stream_large_bodies,
- contentViews= map(lambda v : v.name, contentviews.views)
+ contentViews= [v.name for v in contentviews.views]
)
))
diff --git a/web/src/css/app.less b/web/src/css/app.less
index 6f27f447..353e412a 100644
--- a/web/src/css/app.less
+++ b/web/src/css/app.less
@@ -18,3 +18,4 @@ html {
@import (less) "eventlog.less";
@import (less) "footer.less";
@import (less) "codemirror.less";
+@import (less) "contentview.less";
diff --git a/web/src/css/contentview.less b/web/src/css/contentview.less
new file mode 100644
index 00000000..327dd689
--- /dev/null
+++ b/web/src/css/contentview.less
@@ -0,0 +1,10 @@
+.contentview {
+ .header {
+ font-weight: bold;
+ }
+ .highlight{
+ color: pink;
+ }
+ .offset{ }
+ .text{ }
+}
diff --git a/web/src/js/components/ContentView.jsx b/web/src/js/components/ContentView.jsx
index a93ce395..de4ffd06 100644
--- a/web/src/js/components/ContentView.jsx
+++ b/web/src/js/components/ContentView.jsx
@@ -35,7 +35,7 @@ function ContentView(props) {
const View = ContentViews[contentView] || ContentViews['ViewServer']
return (
- <div>
+ <div className="contentview">
<View flow={flow} message={message} contentView={contentView} readonly={readonly} onChange={onContentChange}/>
<div className="view-options text-center">
diff --git a/web/src/js/components/ContentView/ContentLoader.jsx b/web/src/js/components/ContentView/ContentLoader.jsx
index 9babb8f7..e7a6f379 100644
--- a/web/src/js/components/ContentView/ContentLoader.jsx
+++ b/web/src/js/components/ContentView/ContentLoader.jsx
@@ -53,7 +53,7 @@ export default View => class extends React.Component {
return this.setState({request: undefined, content: ""})
}
- let requestUrl = MessageUtils.getContentURL(props.flow, props.message, props.contentView)
+ let requestUrl = MessageUtils.getContentURL(props.flow, props.message, (View.name == 'ViewServer' ? props.contentView : undefined))
// We use XMLHttpRequest instead of fetch() because fetch() is not (yet) abortable.
let request = new XMLHttpRequest();
diff --git a/web/src/js/components/ContentView/ContentViews.jsx b/web/src/js/components/ContentView/ContentViews.jsx
index 732f9f5e..89e97267 100644
--- a/web/src/js/components/ContentView/ContentViews.jsx
+++ b/web/src/js/components/ContentView/ContentViews.jsx
@@ -28,26 +28,8 @@ function ViewRaw({ content, readonly, onChange }) {
}
ViewRaw = ContentLoader(ViewRaw)
-
-const isJSON = /^application\/json$/i
-ViewJSON.matches = msg => isJSON.test(MessageUtils.getContentType(msg))
-ViewJSON.propTypes = {
- content: React.PropTypes.string.isRequired,
-}
-function ViewJSON({ content }) {
- let json = content
- try {
- json = JSON.stringify(JSON.parse(content), null, 2);
- } catch (e) {
- // @noop
- }
- return <pre>{json}</pre>
-}
-ViewJSON = ContentLoader(ViewJSON)
-
-
ViewAuto.matches = () => false
-ViewAuto.findView = msg => [ViewImage, ViewJSON, ViewRaw].find(v => v.matches(msg)) || ViewRaw
+ViewAuto.findView = msg => [ViewImage, ViewRaw].find(v => v.matches(msg)) || ViewRaw
ViewAuto.propTypes = {
message: React.PropTypes.object.isRequired,
flow: React.PropTypes.object.isRequired,
@@ -57,14 +39,26 @@ function ViewAuto({ message, flow, readonly, onChange }) {
return <View message={message} flow={flow} readonly={readonly} onChange={onChange}/>
}
-function ViewServer({contentView, content}){
+function ViewServer({content, contentView}){
+ let data = JSON.parse(content)
return <div>
- <pre>load from server this view: {contentView}</pre>
- <pre>{content}</pre>
+ {contentView != data.description &&
+ <div className="alert alert-warning">{data.description}</div>
+ }
+ <pre>
+ {data.lines.map((line, i) =>
+ <div key={`line${i}`}>
+ {line.map((tuple, j) =>
+ <span key={`tuple${j}`} className={tuple[0]}>
+ {tuple[1]}
+ </span>
+ )}
+ </div>
+ )}
+ </pre>
</div>
-
}
ViewServer = ContentLoader(ViewServer)
-export { ViewImage, ViewRaw, ViewAuto, ViewJSON, ViewServer }
+export { ViewImage, ViewRaw, ViewAuto, ViewServer }
diff --git a/web/src/js/components/ContentView/ViewSelector.jsx b/web/src/js/components/ContentView/ViewSelector.jsx
index c3e1e105..423cc157 100644
--- a/web/src/js/components/ContentView/ViewSelector.jsx
+++ b/web/src/js/components/ContentView/ViewSelector.jsx
@@ -38,7 +38,7 @@ function ViewSelector({ message, contentViews }) {
<ViewButton name="ViewAuto">auto: {autoViewName}</ViewButton>
{Object.keys(ContentViews).map(name =>
- name !== "ViewAuto" &&
+ name !== "ViewAuto" && name !== "ViewServer" &&
<ViewButton key={name} name={name}>{name.toLowerCase().replace('view', '')}</ViewButton>
)}
diff --git a/web/src/js/flow/utils.js b/web/src/js/flow/utils.js
index 0232e753..b8435aa0 100644
--- a/web/src/js/flow/utils.js
+++ b/web/src/js/flow/utils.js
@@ -49,8 +49,8 @@ export var MessageUtils = {
} else if (message === flow.response) {
message = "response";
}
- return "/flows/" + flow.id + "/" + message + "/content" + (view ? "?content_view="+view : "");
- },
+ return `/flows/${flow.id}/${message}/content` + (view ? `?cv=${view}` : '');
+ }
};
export var RequestUtils = _.extend(MessageUtils, {