combine clientside and serverside contentviews

This commit is contained in:
Clemens 2016-07-29 09:45:15 +02:00
parent 2807329fb2
commit a56c2ca731
6 changed files with 93 additions and 86 deletions

View File

@ -306,36 +306,6 @@ 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()
@ -369,21 +339,69 @@ 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
class FlowContentView(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")
self.write(dict(
lines=list(lines),
description=description
))
else:
self.write(message.raw_content)
if enc:
description = " ".join([enc, description])
return description, lines
def get(self, flow_id, message, content_view):
message = getattr(self.flow, message)
original_cd = message.headers.get("Content-Disposition", None)
filename = None
if original_cd:
filename = re.search("filename=([\w\" \.\-\(\)]+)", original_cd)
if filename:
filename = filename.group(1)
if not filename:
filename = self.flow.request.path.split("?")[0].split("/")[-1]
filename = re.sub(r"[^\w\" \.\-\(\)]", "", filename)
cd = "attachment; filename={}".format(filename)
self.set_header("Content-Disposition", cd)
self.set_header("Content-Type", "application/json")
self.set_header("X-Content-Type-Options", "nosniff")
self.set_header("X-Frame-Options", "DENY")
self.set_header("Content-Encoding", "")
description, lines = self._get_content_view(
message, contentviews.get(content_view.replace('_', ' '))
)
self.write(dict(
lines=list(lines),
description=description
))
class Events(RequestHandler):
@ -412,7 +430,7 @@ class Settings(RequestHandler):
stickyauth=self.master.options.stickyauth,
stickycookie=self.master.options.stickycookie,
stream= self.master.options.stream_large_bodies,
contentViews= [v.name for v in contentviews.views]
contentViews= [v.name.replace(' ', '_') for v in contentviews.views]
)
))
@ -477,6 +495,7 @@ class Application(tornado.web.Application):
(r"/flows/(?P<flow_id>[0-9a-f\-]+)/replay", ReplayFlow),
(r"/flows/(?P<flow_id>[0-9a-f\-]+)/revert", RevertFlow),
(r"/flows/(?P<flow_id>[0-9a-f\-]+)/(?P<message>request|response)/content", FlowContent),
(r"/flows/(?P<flow_id>[0-9a-f\-]+)/(?P<message>request|response)/content/(?P<content_view>[0-9a-zA-Z\-\_]+)", FlowContentView),
(r"/settings", Settings),
(r"/clear", ClearAll),
]

View File

@ -1,10 +1,14 @@
.contentview {
.header {
font-weight: bold;
font-weight: bold;
}
.highlight{
color: pink;
font-weight: bold;
}
.offset{
color: blue
}
.text{
}
.offset{ }
.text{ }
}

View File

@ -18,31 +18,19 @@ function ViewImage({ flow, message }) {
)
}
ViewRaw.matches = () => true
ViewRaw.propTypes = {
Edit.propTypes = {
content: React.PropTypes.string.isRequired,
}
function ViewRaw({ content, readonly, onChange }) {
return readonly ? <pre>{content}</pre> : <CodeEditor content={content} onChange={onChange}/>
}
ViewRaw = ContentLoader(ViewRaw)
ViewAuto.matches = () => false
ViewAuto.findView = msg => [ViewImage, ViewRaw].find(v => v.matches(msg)) || ViewRaw
ViewAuto.propTypes = {
message: React.PropTypes.object.isRequired,
flow: React.PropTypes.object.isRequired,
}
function ViewAuto({ message, flow, readonly, onChange }) {
const View = ViewAuto.findView(message)
return <View message={message} flow={flow} readonly={readonly} onChange={onChange}/>
function Edit({ content, onChange }) {
return <CodeEditor content={content} onChange={onChange}/>
}
Edit = ContentLoader(Edit)
function ViewServer({content, contentView, message, flow}){
function ViewServer(props){
const {content, contentView, message} = props
let data = JSON.parse(content)
let showImage = isImage.test(MessageUtils.getContentType(message))
return <div>
{contentView != data.description &&
@ -59,14 +47,12 @@ function ViewServer({content, contentView, message, flow}){
</div>
)}
</pre>
{showImage &&
<div className="flowview-image">
<img src={MessageUtils.getContentURL(flow, message)} alt="preview" className="img-thumbnail"/>
</div>
{ViewImage.matches(message) &&
<ViewImage {...props} />
}
</div>
}
ViewServer = ContentLoader(ViewServer)
export { ViewImage, ViewRaw, ViewAuto, ViewServer }
export { Edit, ViewServer, ViewImage }

View File

@ -24,25 +24,18 @@ ViewButton = connect(state => ({
ViewSelector.propTypes = {
message: PropTypes.object.isRequired,
}
function ViewSelector({ message, contentViews }) {
let autoView = ContentViews.ViewAuto.findView(message)
let autoViewName = (autoView.displayName || autoView.name)
.toLowerCase()
.replace('view', '')
.replace(/ContentLoader\((.+)\)/,"$1")
function ViewSelector({contentViews, isEdit }) {
let edit = ContentViews.Edit.displayName
return (
<div className="view-selector btn-group btn-group-xs">
{Object.keys(ContentViews).map(name =>
name === "ViewRaw" &&
<ViewButton key={name} name={name}>{name.toLowerCase().replace('view', '')}</ViewButton>
{contentViews.map(name =>
<ViewButton key={name} name={name}>{name.toLowerCase().replace('_', ' ')}</ViewButton>
)}
{contentViews.map(name =>
<ViewButton key={name} name={name}>{name.toLowerCase().replace('view', '')}</ViewButton>
)}
{isEdit &&
<ViewButton key={edit} name={edit}>{edit.toLowerCase()}</ViewButton>
}
</div>
)
@ -50,5 +43,6 @@ function ViewSelector({ message, contentViews }) {
export default connect (
state => ({
contentViews: state.settings.contentViews
contentViews: state.settings.contentViews,
isEdit: !!state.ui.flow.modifiedFlow,
}))(ViewSelector)

View File

@ -19,12 +19,14 @@ const defaultState = {
}
export default function reducer(state = defaultState, action) {
let wasInEditMode = !!(state.modifiedFlow)
switch (action.type) {
case START_EDIT:
return {
...state,
modifiedFlow: action.flow,
contentView: 'Edit'
}
case UPDATE_EDIT:
@ -38,6 +40,7 @@ export default function reducer(state = defaultState, action) {
...state,
modifiedFlow: false,
displayLarge: false,
contentView: (wasInEditMode ? 'Auto' : state.contentView)
}
case flowsActions.UPDATE:
@ -49,6 +52,7 @@ export default function reducer(state = defaultState, action) {
...state,
modifiedFlow: false,
displayLarge: false,
contentView: (wasInEditMode ? 'Auto' : state.contentView)
}
} else {
return state

View File

@ -49,7 +49,7 @@ export var MessageUtils = {
} else if (message === flow.response) {
message = "response";
}
return `/flows/${flow.id}/${message}/content` + (view ? `?cv=${view}` : '');
return `/flows/${flow.id}/${message}/content` + (view ? `/${view}` : '');
}
};