@@ -175,7 +180,7 @@ class App extends React.Component {
{
- !(isTextResponse(request)) ? "Not text" :
+ !(isTextBody(request)) ? "Not text" :
new TextDecoder().decode(request.body)
}
@@ -189,7 +194,7 @@ class App extends React.Component {
{
!(flowTab === 'Response') ? null :
!(response.body && response.body.byteLength) ?
No response
:
- !(isTextResponse(response)) ?
Not text response
:
+ !(isTextBody(response)) ?
Not text response
:
{new TextDecoder().decode(response.body)}
diff --git a/addon/web/client/src/components/BreakPoint.js b/addon/web/client/src/components/BreakPoint.js
index 18399dd..cc83ad1 100644
--- a/addon/web/client/src/components/BreakPoint.js
+++ b/addon/web/client/src/components/BreakPoint.js
@@ -102,7 +102,7 @@ class BreakPoint extends React.Component {
-
+
)
diff --git a/addon/web/client/src/components/EditFlow.js b/addon/web/client/src/components/EditFlow.js
new file mode 100644
index 0000000..fe8536b
--- /dev/null
+++ b/addon/web/client/src/components/EditFlow.js
@@ -0,0 +1,208 @@
+import React from 'react'
+import Button from 'react-bootstrap/Button'
+import Modal from 'react-bootstrap/Modal'
+import Form from 'react-bootstrap/Form'
+import Alert from 'react-bootstrap/Alert'
+
+import { sendMessageEnum, buildMessageEdit } from '../message'
+import { isTextBody } from '../utils'
+
+
+const stringifyRequest = request => {
+ const firstLine = `${request.method} ${request.url}`
+ const headerLines = Object.keys(request.header).map(key => {
+ const valstr = request.header[key].join(' \t ') // for parse convenience
+ return `${key}: ${valstr}`
+ }).join('\n')
+
+ let bodyLines = ''
+ if (request.body && isTextBody(request)) bodyLines = new TextDecoder().decode(request.body)
+
+ return `${firstLine}\n\n${headerLines}\n\n${bodyLines}`
+}
+
+const parseRequest = content => {
+ const sections = content.split('\n\n')
+ if (sections.length !== 3) return
+
+ const [firstLine, headerLines, bodyLines] = sections
+ const [method, url] = firstLine.split(' ')
+ if (!method || !url) return
+
+ const header = {}
+ for (const line of headerLines.split('\n')) {
+ const [key, vals] = line.split(': ')
+ if (!key || !vals) return
+ header[key] = vals.split(' \t ')
+ }
+
+ let body = null
+ if (bodyLines) body = new TextEncoder().encode(bodyLines)
+
+ return {
+ method,
+ url,
+ header,
+ body,
+ }
+}
+
+const stringifyResponse = response => {
+ const firstLine = `${response.statusCode}`
+ const headerLines = Object.keys(response.header).map(key => {
+ const valstr = response.header[key].join(' \t ') // for parse convenience
+ return `${key}: ${valstr}`
+ }).join('\n')
+
+ let bodyLines = ''
+ if (response.body && isTextBody(response)) bodyLines = new TextDecoder().decode(response.body)
+
+ return `${firstLine}\n\n${headerLines}\n\n${bodyLines}`
+}
+
+const parseResponse = content => {
+ const sections = content.split('\n\n')
+ if (sections.length !== 3) return
+
+ const [firstLine, headerLines, bodyLines] = sections
+ const statusCode = parseInt(firstLine)
+ if (isNaN(statusCode)) return
+
+ const header = {}
+ for (const line of headerLines.split('\n')) {
+ const [key, vals] = line.split(': ')
+ if (!key || !vals) return
+ header[key] = vals.split(' \t ')
+ }
+
+ let body = null
+ if (bodyLines) body = new TextEncoder().encode(bodyLines)
+
+ return {
+ statusCode,
+ header,
+ body,
+ }
+}
+
+
+class EditFlow extends React.Component {
+ constructor(props) {
+ super(props)
+
+ this.state = {
+ show: false,
+ alertMsg: '',
+ content: '',
+ }
+
+ this.handleClose = this.handleClose.bind(this)
+ this.handleShow = this.handleShow.bind(this)
+ this.handleSave = this.handleSave.bind(this)
+ }
+
+ showAlert(msg) {
+ this.setState({ alertMsg: msg })
+ }
+
+ handleClose() {
+ this.setState({ show: false })
+ }
+
+ handleShow() {
+ const { flow } = this.props
+ const when = flow.response ? 'response' : 'request'
+
+ let content = ''
+ if (when === 'request') {
+ content = stringifyRequest(flow.request)
+ } else {
+ content = stringifyResponse(flow.response)
+ }
+
+ this.setState({ show: true, alertMsg: '', content })
+ }
+
+ handleSave() {
+ const { flow } = this.props
+ const when = flow.response ? 'response' : 'request'
+
+ const { content } = this.state
+
+ if (when === 'request') {
+ const request = parseRequest(content)
+ if (!request) {
+ this.showAlert('parse error')
+ return
+ }
+
+ this.props.onChangeRequest(request)
+ this.handleClose()
+ } else {
+ const response = parseResponse(content)
+ if (!response) {
+ this.showAlert('parse error')
+ return
+ }
+
+ this.props.onChangeResponse(response)
+ this.handleClose()
+ }
+ }
+
+ render() {
+ const { flow } = this.props
+ if (!flow.waitIntercept) return null
+
+ const { alertMsg } = this.state
+
+ const when = flow.response ? 'response' : 'request'
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ Edit {when === 'request' ? 'Request' : 'Response'}
+
+
+
+
+ { this.setState({ content: e.target.value }) }} />
+
+ {
+ !alertMsg ? null : {alertMsg}
+ }
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+export default EditFlow
diff --git a/addon/web/client/src/utils.js b/addon/web/client/src/utils.js
index 73caa4b..a175224 100644
--- a/addon/web/client/src/utils.js
+++ b/addon/web/client/src/utils.js
@@ -1,9 +1,9 @@
-export const isTextResponse = response => {
- if (!response) return false
- if (!response.header) return false
- if (!response.header['Content-Type']) return false
+export const isTextBody = payload => {
+ if (!payload) return false
+ if (!payload.header) return false
+ if (!payload.header['Content-Type']) return false
- return /text|javascript|json/.test(response.header['Content-Type'].join(''))
+ return /text|javascript|json/.test(payload.header['Content-Type'].join(''))
}
export const getSize = response => {
diff --git a/addon/web/conn.go b/addon/web/conn.go
index d7b4c86..f9f730a 100644
--- a/addon/web/conn.go
+++ b/addon/web/conn.go
@@ -148,7 +148,7 @@ func (c *concurrentConn) waitIntercept(f *flow.Flow, after *messageFlow) {
f.Request.Header = msg.request.Header
f.Request.Body = msg.request.Body
} else if msg.mType == messageTypeChangeResponse {
- // TODO: statusCode
+ f.Response.StatusCode = msg.response.StatusCode
f.Response.Header = msg.response.Header
f.Response.Body = msg.response.Body
}