UNPKG

luminati-proxy-stripped

Version:

A configurable local proxy for luminati.io

238 lines (230 loc) 9.27 kB
// LICENSE_CODE ZON ISC 'use strict'; /*jslint react:true, es6:true*/ import React from 'react'; import Pure_component from '../../www/util/pub/pure_component.js'; import $ from 'jquery'; import {Input, Select, Loader, Modal, Warnings, Nav, Tooltip, Add_icon, Remove_icon} from './common.js'; import classnames from 'classnames'; import ajax from '../../util/ajax.js'; import zurl from '../../util/url.js'; import {ga_event} from './util.js'; import Preview from './har_preview.js'; class Proxy_tester extends Pure_component { state = {}; title = 'Proxy Tester'; subtitle = 'Emulate requests from your proxies to any target URL'; update_response = response=>this.setState({response}); clear_response = ()=>this.setState({response: undefined}); render(){ return <div className="proxy_tester vbox"> <Nav title={this.title} subtitle={this.subtitle}/> <Request update_response={this.update_response}/> <Preview cur_preview={this.state.response} close_preview={this.clear_response}/> </div>; } } class Request extends Pure_component { first_header = {idx: 0, header: '', value: ''}; default_state = { headers: [this.first_header], max_idx: 0, params: {url: 'http://lumtest.com/myip.json', method: 'GET'}, }; state = {...this.default_state, show_loader: false}; componentDidMount(){ setTimeout(()=>{ const url_o = zurl.parse(document.location.href); const qs_o = zurl.qs_parse((url_o.search||'').substr(1)); const url = qs_o.url||this.state.params.url; const method = qs_o.method||this.state.params.method; const port = qs_o.port||this.state.params.port; this.setdb_on('head.proxies_running', proxies=>{ if (!proxies||!proxies.length) return; this.setState({proxies}); this.setState(prev_state=>{ const def_port = proxies[0].port; this.default_state.params.proxy = def_port; return {params: {...prev_state.params, proxy: port||def_port, method, url}}; }); }); }); } add_header = ()=>{ ga_event('proxy_tester', 'add header'); this.setState(prev_state=>({ headers: [...prev_state.headers, {idx: prev_state.max_idx+1, header: '', value: ''}], max_idx: prev_state.max_idx+1, })); }; remove_header = idx=>{ ga_event('proxy_tester', 'remove header'); if (this.state.headers.length==1) return this.setState({headers: [this.first_header]}); this.setState(prev_state=>( {headers: prev_state.headers.filter(h=>h.idx!=idx)})); }; update_header = (idx, field, value)=>{ this.setState(prev_state=>({ headers: prev_state.headers.map(h=>{ if (h.idx!=idx) return h; return {...h, [field]: value}; }), })); }; update_params = (field, value)=>{ this.setState(prev_state=>({ params: {...prev_state.params, [field]: value}})); }; go = ()=>{ ga_event('proxy_tester', 'run test'); if (!this.state.params.proxy) { ga_event('proxy_tester', 'no proxy chosen'); this.setState({warnings: [{msg: 'You need to choose a proxy port first'}]}); $('#warnings_modal').modal(); return; } const url = '/api/test/'+this.state.params.proxy; const data = { headers: this.state.headers.reduce((acc, el)=>{ if (!el.header) return acc; return {...acc, [el.header]: el.value}; }, {}), method: this.state.params.method, url: this.state.params.url, }; this.setState({show_loader: true}); const _this = this; this.etask(function*(){ this.on('uncaught', e=>{ console.error(e); _this.setState({show_loader: false}); ga_event('proxy_tester', 'unexpected error', e.message); }); const resp = yield ajax.json({method: 'POST', url, data, timeout: 60000}); _this.setState({show_loader: false}); if (resp.error) { _this.setState({warnings: [{msg: resp.error}]}); $('#warnings_modal').modal(); ga_event('proxy_tester', 'response has errors', resp.error); } else { ga_event('proxy_tester', 'response successful'); _this.props.update_response(resp); } }); }; render(){ return <div className="panel no_border request"> <Loader show={this.state.show_loader}/> <Modal className="warnings_modal" id="warnings_modal" title="Warnings:" no_cancel_btn> <Warnings warnings={this.state.warnings}/> </Modal> <div> <Request_params params={this.state.params} update={this.update_params} proxies={this.state.proxies}/> <Headers headers={this.state.headers} clicked_remove={this.remove_header} clicked_add={this.add_header} update={this.update_header}/> <div className="footer_buttons"> <Tooltip title="Send a test request"> <button onClick={this.go} className="btn btn_lpm btn_lpm_primary">Go</button> </Tooltip> </div> </div> </div>; } } const Request_params = ({params, update, proxies})=>{ proxies = (proxies||[]).map(p=>({key: p.port, value: p.port})); const methods = [{key: 'GET', value: 'GET'}, {key: 'POST', value: 'POST'}]; const method_tip = `Method of a test request. Leave GET if you don't know what to choose`; return <div className="request_params"> <Field params={params} update={update} name="proxy" type="select" data={proxies} tooltip="Choose a proxy port that will be used for this test"/> <Field params={params} update={update} name="url" type="text" tooltip="URL that Proxy Tester will use to send a test request"/> <Field params={params} update={update} name="method" type="select" data={methods} tooltip={method_tip}/> </div>; }; const Field = ({type, update, name, params, tooltip, ...props})=>{ const fields = {proxy: 'Proxy port', url: 'URL', method: 'Method'}; const on_change_wrapper = val=>{ if (name!='url') ga_event('proxy_tester', 'edit '+name); update(name, val); }; const on_blur = ()=>{ if (name=='url') ga_event('proxy_tester', 'edit url'); }; let Comp; if (type=='select') Comp = Select; else Comp = Input; const title = fields[name]; return <Tooltip title={tooltip}> <div className={classnames('field', name)}> {title && <div className="title">{fields[name]}</div>} <Comp on_change_wrapper={on_change_wrapper} type={type} val={params[name]} {...props} on_blur={on_blur}/> </div> </Tooltip>; }; const Headers = ({headers, clicked_remove, clicked_add, update})=> <div className="headers"> {headers.map((h, i)=> <New_header_params clicked_remove={clicked_remove} last={i+1==headers.length} clicked_add={clicked_add} header={h} key={h.idx} update={update}/> )} </div>; class New_header_params extends Pure_component { input_changed = field=>value=> this.props.update(this.props.header.idx, field, value); header_tip = `Header name that will be sent along with the request`; value_tip = `Value of the header that will be sent along with the request`; render(){ const {clicked_add, clicked_remove, header, last} = this.props; return <div className="header_line"> <Tooltip title={this.header_tip}> <div className="header_input"> <Input val={header.header} type="text" placeholder="Header" on_change_wrapper={this.input_changed('header')}/> </div> </Tooltip> <Tooltip title={this.value_tip}> <div className="value_input"> <Input val={header.value} type="text" placeholder="Value" on_change_wrapper={this.input_changed('value')}/> </div> </Tooltip> <div className="action_icons"> <Remove_icon tooltip="Remove header" click={()=>clicked_remove(header.idx)}/> {last && <Add_icon tooltip="Add header" click={clicked_add}/>} </div> </div>; } } export default Proxy_tester;