How to disable CSRF check in Spring WebService / Spring WS Security application? - spring
I have an application that uses Spring WS and Spring WS security for creating SOAP web services. I am getting the following exception.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><script type="text/javascript">(window.NREUM||(NREUM={})).loader_config={licenseKey:"d89ec68706",applicationID:"74176617"};window.NREUM||(NREUM={}),__nr_require=function(e,n,t){function r(t){if(!n[t]){var i=n[t]={exports:{}};e[t][0].call(i.exports,function(n){var i=e[t][1][n];return r(i||n)},i,i.exports)}return n[t].exports}if("function"==typeof __nr_require)return __nr_require;for(var i=0;i<t.length;i++)r(t[i]);return r}({1:[function(e,n,t){function r(){}function i(e,n,t){return function(){return o(e,[u.now()].concat(f(arguments)),n?null:this,t),n?void 0:this}}var o=e("handle"),a=e(4),f=e(5),c=e("ee").get("tracer"),u=e("loader"),s=NREUM;"undefined"==typeof window.newrelic&&(newrelic=s);var p=["setPageViewName","setCustomAttribute","setErrorHandler","finished","addToTrace","inlineHit","addRelease"],l="api-",d=l+"ixn-";a(p,function(e,n){s[n]=i(l+n,!0,"api")}),s.addPageAction=i(l+"addPageAction",!0),s.setCurrentRouteName=i(l+"routeName",!0),n.exports=newrelic,s.interaction=function(){return(new r).get()};var m=r.prototype={createTracer:function(e,n){var t={},r=this,i="function"==typeof n;return o(d+"tracer",[u.now(),e,t],r),function(){if(c.emit((i?"":"no-")+"fn-start",[u.now(),r,i],t),i)try{return n.apply(this,arguments)}catch(e){throw c.emit("fn-err",[arguments,this,e],t),e}finally{c.emit("fn-end",[u.now()],t)}}}};a("actionText,setName,setAttribute,save,ignore,onEnd,getContext,end,get".split(","),function(e,n){m[n]=i(d+n)}),newrelic.noticeError=function(e,n){"string"==typeof e&&(e=new Error(e)),o("err",[e,u.now(),!1,n])}},{}],2:[function(e,n,t){function r(e,n){var t=e.getEntries();t.forEach(function(e){"first-paint"===e.name?c("timing",["fp",Math.floor(e.startTime)]):"first-contentful-paint"===e.name&&c("timing",["fcp",Math.floor(e.startTime)])})}function i(e,n){var t=e.getEntries();t.length>0&&c("lcp",[t[t.length-1]])}function o(e){if(e instanceof s&&!l){var n,t=Math.round(e.timeStamp);n=t>1e12?Date.now()-t:u.now()-t,l=!0,c("timing",["fi",t,{type:e.type,fid:n}])}}if(!("init"in NREUM&&"page_view_timing"in NREUM.init&&"enabled"in NREUM.init.page_view_timing&&NREUM.init.page_view_timing.enabled===!1)){var a,f,c=e("handle"),u=e("loader"),s=NREUM.o.EV;if("PerformanceObserver"in window&&"function"==typeof window.PerformanceObserver){a=new PerformanceObserver(r),f=new PerformanceObserver(i);try{a.observe({entryTypes:["paint"]}),f.observe({entryTypes:["largest-contentful-paint"]})}catch(p){}}if("addEventListener"in document){var l=!1,d=["click","keydown","mousedown","pointerdown","touchstart"];d.forEach(function(e){document.addEventListener(e,o,!1)})}}},{}],3:[function(e,n,t){function r(e,n){if(!i)return!1;if(e!==i)return!1;if(!n)return!0;if(!o)return!1;for(var t=o.split("."),r=n.split("."),a=0;a<r.length;a++)if(r[a]!==t[a])return!1;return!0}var i=null,o=null,a=/Version\/(\S+)\s+Safari/;if(navigator.userAgent){var f=navigator.userAgent,c=f.match(a);c&&f.indexOf("Chrome")===-1&&f.indexOf("Chromium")===-1&&(i="Safari",o=c[1])}n.exports={agent:i,version:o,match:r}},{}],4:[function(e,n,t){function r(e,n){var t=[],r="",o=0;for(r in e)i.call(e,r)&&(t[o]=n(r,e[r]),o+=1);return t}var i=Object.prototype.hasOwnProperty;n.exports=r},{}],5:[function(e,n,t){function r(e,n,t){n||(n=0),"undefined"==typeof t&&(t=e?e.length:0);for(var r=-1,i=t-n||0,o=Array(i<0?0:i);++r<i;)o[r]=e[n+r];return o}n.exports=r},{}],6:[function(e,n,t){n.exports={exists:"undefined"!=typeof window.performance&&window.performance.timing&&"undefined"!=typeof window.performance.timing.navigationStart}},{}],ee:[function(e,n,t){function r(){}function i(e){function n(e){return e&&e instanceof r?e:e?c(e,f,o):o()}function t(t,r,i,o){if(!l.aborted||o){e&&e(t,r,i);for(var a=n(i),f=v(t),c=f.length,u=0;u<c;u++)f[u].apply(a,r);var p=s[y[t]];return p&&p.push([b,t,r,a]),a}}function d(e,n){h[e]=v(e).concat(n)}function m(e,n){var t=h[e];if(t)for(var r=0;r<t.length;r++)t[r]===n&&t.splice(r,1)}function v(e){return h[e]||[]}function g(e){return p[e]=p[e]||i(t)}function w(e,n){u(e,function(e,t){n=n||"feature",y[t]=n,n in s||(s[n]=[])})}var h={},y={},b={on:d,addEventListener:d,removeEventListener:m,emit:t,get:g,listeners:v,context:n,buffer:w,abort:a,aborted:!1};return b}function o(){return new r}function a(){(s.api||s.feature)&&(l.aborted=!0,s=l.backlog={})}var f="nr#context",c=e("gos"),u=e(4),s={},p={},l=n.exports=i();l.backlog=s},{}],gos:[function(e,n,t){function r(e,n,t){if(i.call(e,n))return e[n];var r=t();if(Object.defineProperty&&Object.keys)try{return Object.defineProperty(e,n,{value:r,writable:!0,enumerable:!1}),r}catch(o){}return e[n]=r,r}var i=Object.prototype.hasOwnProperty;n.exports=r},{}],handle:[function(e,n,t){function r(e,n,t,r){i.buffer([e],r),i.emit(e,n,t)}var i=e("ee").get("handle");n.exports=r,r.ee=i},{}],id:[function(e,n,t){function r(e){var n=typeof e;return!e||"object"!==n&&"function"!==n?-1:e===window?0:a(e,o,function(){return i++})}var i=1,o="nr#id",a=e("gos");n.exports=r},{}],loader:[function(e,n,t){function r(){if(!x++){var e=E.info=NREUM.info,n=d.getElementsByTagName("script")[0];if(setTimeout(s.abort,3e4),!(e&&e.licenseKey&&e.applicationID&&n))return s.abort();u(y,function(n,t){e[n]||(e[n]=t)}),c("mark",["onload",a()+E.offset],null,"api");var t=d.createElement("script");t.src="https://"+e.agent,n.parentNode.insertBefore(t,n)}}function i(){"complete"===d.readyState&&o()}function o(){c("mark",["domContent",a()+E.offset],null,"api")}function a(){return O.exists&&performance.now?Math.round(performance.now()):(f=Math.max((new Date).getTime(),f))-E.offset}var f=(new Date).getTime(),c=e("handle"),u=e(4),s=e("ee"),p=e(3),l=window,d=l.document,m="addEventListener",v="attachEvent",g=l.XMLHttpRequest,w=g&&g.prototype;NREUM.o={ST:setTimeout,SI:l.setImmediate,CT:clearTimeout,XHR:g,REQ:l.Request,EV:l.Event,PR:l.Promise,MO:l.MutationObserver};var h=""+location,y={beacon:"bam.nr-data.net",errorBeacon:"bam.nr-data.net",agent:"js-agent.newrelic.com/nr-1167.min.js"},b=g&&w&&w[m]&&!/CriOS/.test(navigator.userAgent),E=n.exports={offset:f,now:a,origin:h,features:{},xhrWrappable:b,userAgent:p};e(1),e(2),d[m]?(d[m]("DOMContentLoaded",o,!1),l[m]("load",r,!1)):(d[v]("onreadystatechange",i),l[v]("onload",r)),c("mark",["firstbyte",f],null,"api");var x=0,O=e(6)},{}],"wrap-function":[function(e,n,t){function r(e){return!(e&&e instanceof Function&&e.apply&&!e[a])}var i=e("ee"),o=e(5),a="nr#original",f=Object.prototype.hasOwnProperty,c=!1;n.exports=function(e,n){function t(e,n,t,i){function nrWrapper(){var r,a,f,c;try{a=this,r=o(arguments),f="function"==typeof t?t(r,a):t||{}}catch(u){l([u,"",[r,a,i],f])}s(n+"start",[r,a,i],f);try{return c=e.apply(a,r)}catch(p){throw s(n+"err",[r,a,p],f),p}finally{s(n+"end",[r,a,c],f)}}return r(e)?e:(n||(n=""),nrWrapper[a]=e,p(e,nrWrapper),nrWrapper)}function u(e,n,i,o){i||(i="");var a,f,c,u="-"===i.charAt(0);for(c=0;c<n.length;c++)f=n[c],a=e[f],r(a)||(e[f]=t(a,u?f+i:i,o,f))}function s(t,r,i){if(!c||n){var o=c;c=!0;try{e.emit(t,r,i,n)}catch(a){l([a,t,r,i])}c=o}}function p(e,n){if(Object.defineProperty&&Object.keys)try{var t=Object.keys(e);return t.forEach(function(t){Object.defineProperty(n,t,{get:function(){return e[t]},set:function(n){return e[t]=n,n}})}),n}catch(r){l([r])}for(var i in e)f.call(e,i)&&(n[i]=e[i]);return n}function l(n){try{e.emit("internal-error",n)}catch(t){}}return e||(e=i),t.inPlace=u,t.flag=a,t}},{}]},{},["loader"]);</script><script type="text/javascript">window.NREUM||(NREUM={});NREUM.info={"beacon":"bam.nr-data.net","queueTime":0,"licenseKey":"d89ec68706","agent":"","transactionName":"MldVZUJYCkoDABVeWwsdcUReWhBQDQ1OU14EXFBeHlQNXQYPBEBVF1cZUkNLAgMhEBNRYgxXQHxZXQBVBxQARVFLQkVeU1wXSj0VCFJD","applicationID":"74176617","errorBeacon":"bam.nr-data.net","applicationTime":5}</script>
<meta name="robots" content="NONE,NOARCHIVE">
<title>403 Forbidden</title>
<style type="text/css">
html * { padding:0; margin:0; }
body * { padding:10px 20px; }
body * * { padding:0; }
body { font:small sans-serif; background:#eee; }
body>div { border-bottom:1px solid #ddd; }
h1 { font-weight:normal; margin-bottom:.4em; }
h1 span { font-size:60%; color:#666; font-weight:normal; }
#info { background:#f6f6f6; }
#info ul { margin: 0.5em 4em; }
#info p, #summary p { padding-top:10px; }
#summary { background: #ffc; }
#explanation { background:#eee; border-bottom: 0px none; }
</style>
</head>
<body>
<div id="summary">
<h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p>
<p>You are seeing this message because this site requires a CSRF cookie when submitting forms. This cookie is required for security reasons, to ensure that your browser is not being hijacked by third parties.</p>
<p>If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for 'same-origin' requests.</p>
</div>
<div id="explanation">
<p><small>More information is available with DEBUG=True.</small></p>
</div>
</body>
</html>
I'm using spring ws-security to send plain text username-password for authorization.
How do I disable CSRF check in this application?
This is my security-policy.xml.
<xwss:SecurityConfiguration
xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireUsernameToken
passwordDigestRequired="false" nonceRequired="false" />
</xwss:SecurityConfiguration>
Any help is greatly appreciated. Thanks in advance.
Here's how I do it, in pre Spring Security 4:
Custom Request Matcher:
#Component
public class CsrfSecurityRequestMatcher implements RequestMatcher {
private RegexRequestMatcher protectedMatcher = new RegexRequestMatcher("(/path_with_csrf/.*)", null);
#Override
public boolean matches(HttpServletRequest request) {
return protectedMatcher.matches(request);
}
}
Security config:
<security:csrf request-matcher-ref="csrfSecurityRequestMatcher" />
Related
Tailwind css laravel mix add fonts
I am trying to use tailwndo css for a project in laravel and I would like to maintain the nunito font for the whole app but Tailwind has its own font set. Does anybody know how to change it?
Connect the font to the project (as you usually do) and just add your font to tailwind.config.js module.exports = { theme: { fontFamily: { 'sans': ['-apple-system', 'BlinkMacSystemFont', ...], 'serif': ['Georgia', 'Cambria', ...], 'mono': ['SFMono-Regular', 'Menlo', ...], 'your-font': ['Your Font', ...] } } } https://tailwindcss.com/docs/font-family/#app
tailwind.config.js : theme: { extend: { fontFamily: { body: ['Rowdies'] } } }, css\app.css #import url('https://fonts.googleapis.com/css2?family=Rowdies:wght#300&display=swap'); shell: npm run dev or npm run watch now you can use .font-body class in any tag that you want for example: <body class="font-body"> <h1>Hello World!</h1> </body> font + body = font-body fontFamily: { body: ['Open Sans'] } (you can change body)
How to include JS in a page HTML with Apache Sling
In Apache Sling i want include a javascript into a HTML page. Via http://localhost:8080/bin/browser.html/ I created two nodes (then manually): html.html and processing.js. JSON of html.html is: { "jcr:created": "{Date}2018-04-19 20:50:09", "jcr:createdBy": "admin", "jcr:primaryType": "{Name}nt:file", "jcr:content": { "jcr:data": "/bin/cpm/nodes/property.bin/apps/res/html.html/_jcr_content?name=jcr%3Adata", "jcr:lastModified": "{Date}2018-04-19 20:50:09", "jcr:lastModifiedBy": "admin", "jcr:mimeType": "text/html", "jcr:primaryType": "{Name}nt:resource", "jcr:uuid": "ed3121b3-580c-46b2-acc6-7029cdb6f1c3" } } JSON of processing.js is: { "jcr:data": "/bin/cpm/nodes/property.bin/apps/res/processing.js?name=jcr%3Adata", "jcr:lastModified": "{Date}2018-04-19 21:32:40", "jcr:lastModifiedBy": "admin", "jcr:mimeType": "text/javascript", "jcr:primaryType": "{Name}nt:resource", "jcr:uuid": "74fd137a-3b37-4893-b443-bd086a4fb4d7" } In page HTML I include processing.js with <script> tag in the <head> tag look like following: <head> <script type="text/javascript" src="processing.js"></script> </head> Both nodes is located on the same path, that's "apps". I get error in console of Mozilla Firefox: http://i68.tinypic.com/a0cj88.png In error.log file I get this error: 19.04.2018 22:13:32.813 *INFO* [0:0:0:0:0:0:0:1 [1524168812811] GET /apps/processing.js HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Resource /apps/processing.js not found Why did I get this error? How can i fix it? Please help me. Thanks you very much in advance.
Try to add the resource path to the src of your file. <script type="text/javascript" src="${resource.path}/processing.js"></script> THat should solve the problem
Sencha Touch JsonP Callback doesn't recognise Ext object
I am using Sencha Touch's Ext.data.JsonP.request call in the following manner: Ext.data.JsonP.request({ url: 'php/apiCustomer.php', callbackKey: 'callback', scope: this, params: { action: 'AttemptLogin', email: name, password: password, format: 'json' }, success: function(result, request) { // ... } }); The response looks like this: Ext.data.JsonP.callback1({...}) Under normal circumstances, this works exactly correctly. However, when running the built production code, I get the following error: Uncaught TypeError: Cannot read property 'JsonP' of undefined I did my own sleuthing and discovered that when the callback is evaluated, this is all that is known of the 'Ext' object: Ext.blink Ext.microloaded Ext.filterPlatform Has anyone encountered this before? EDIT: The contents of my app.json file are: { /** * The application's namespace, used by Sencha Command to generate classes */ "name": "MyApp", /** * The file path to this application's front HTML document, relative to this app.json file */ "indexHtmlPath": "index.html", /** * The absolute URL to this application in development environment, i.e: the URL to run this application * on your web browser during development, e.g: "http://localhost/myapp/index.html". * * This value is needed when build to resolve your application's dependencies if it requires server-side resources * that are not accessible via file system protocol. */ "url": null, /** * List of all JavaScript assets in the right execution order. * Each item is an object with the following format: * { * "path": "path/to/script.js" // Path to file, if local file it must be relative to this app.json file * "remote": true // (Optional) * // - Defaults to undefined (falsey) to signal a local file which will be copied * // - Specify true if this file is a remote file which will not to be copied * "update": "delta" // (Optional) * // - If not specified, this file will only be loaded once, and * // cached inside localStorage until this value is changed. * // - "delta" to enable over-the-air delta update for this file * // - "full" means full update will be made when this file changes * "x-bootstrap": true // (Optional) * // Indicates a development mode only dependency. * // These files will not be copied into the build directory or referenced * // in the generate app.json manifest for the micro loader. * * } */ "js": [ { "path": "touch/sencha-touch.js", "x-bootstrap": true }, { "path": "bootstrap.js", "x-bootstrap": true }, { "path": "app.js", "bundle": true, /* Indicates that all class dependencies are concatenated into this file when build */ "update": "delta" } ], /** * List of all CSS assets in the right inclusion order. * Each item is an object with the following format: * { * "path": "path/to/item.css" // Path to file, if local file it must be relative to this app.json file * "remote": true // (Optional) * // - Defaults to undefined (falsey) to signal a local file which will be copied * // - Specify true if this file is a remote file which will not to be copied * "update": "delta" // (Optional) * // - If not specified, this file will only be loaded once, and * // cached inside localStorage until this value is changed to either one below * // - "delta" to enable over-the-air delta update for this file * // - "full" means full update will be made when this file changes * * } */ "css": [ { "path": "resources/css/app.css", "update": "delta" }, { "path": "resources/css/custom.css", "update": "delta" } ], /** * Used to automatically generate cache.manifest (HTML 5 application cache manifest) file when you build */ "appCache": { /** * List of items in the CACHE MANIFEST section */ "cache": [ "index.html" ], /** * List of items in the NETWORK section */ "network": [ "*" ], /** * List of items in the FALLBACK section */ "fallback": [] }, /** * Extra resources to be copied along when build */ "resources": [ "resources/images", "resources/icons", "resources/startup" ], /** * File / directory name matchers to ignore when copying to the builds, must be valid regular expressions */ "ignore": [ "\.svn$" ], /** * Directory path to store all previous production builds. Note that the content generated inside this directory * must be kept intact for proper generation of deltas between updates */ "archivePath": "archive", /** * List of package names to require for the cmd build process */ "requires": [ ], /** * Uniquely generated id for this application, used as prefix for localStorage keys. * Normally you should never change this value. */ "id": "52d77512-9617-4982-b007-98bfaed1312e" } The contents of index.html are: <!DOCTYPE HTML> <html manifest="" lang="en-US"> <head> <meta charset="UTF-8"> <title>MyApp</title> <link rel="apple-touch-icon" href="icon.png" /> <style type="text/css"> /** * Example of an initial loading indicator. * It is recommended to keep this as minimal as possible to provide instant feedback * while other resources are still being loaded for the first time */ html, body { height: 100%; background-color: #DB3040 } #appLoadingIndicator { position: absolute; top: 50%; margin-top: -15px; text-align: center; width: 100%; height: 30px; -webkit-animation-name: appLoadingIndicator; -webkit-animation-duration: 0.5s; -webkit-animation-iteration-count: infinite; -webkit-animation-direction: linear; } #appLoadingIndicator > * { background-color: #FFFFFF; display: inline-block; height: 30px; -webkit-border-radius: 15px; margin: 0 5px; width: 30px; opacity: 0.8; } #-webkit-keyframes appLoadingIndicator{ 0% { opacity: 0.8 } 50% { opacity: 0 } 100% { opacity: 0.8 } } </style> <!-- The line below must be kept intact for Sencha Command to build your application --> <script id="microloader" type="text/javascript" src=".sencha/app/microloader/development.js"></script> </head> <body> <div id="appLoadingIndicator"> <div></div> <div></div> <div></div> </div> </body> </html>
It turns out that the issue was that the Ext object was not in a global scope and thus not visible from the callback code. To fix it, I modified the minified app.js code in the following ways: Added 'MyApp=null;' to the beginning of the file, Replaced 'var MyApp=MyApp||()' with 'MyApp=MyApp||()'. Replaced 'var Ext=Ext||()' with 'Ext=Ext||()'. This placed the right stuff in the global namespace.
SASS breaks my selector
I'm having trouble with SASS. Locally I have this selector: #featured-categories{ ul{ li{ width: 33.33%; } } } which works as expected. Deployed (and compressed) however this is compiling to: #featured-categoriesulli{width: 33.33%;} which of course is an invalid selector. The more straight more forward formulation: #featured-categories ul li{ width: 33.33%; } behaves in the same way - i.e. compiles to something munged and broken. The only way I can get this to compile is to add redundant rules between the elements of the selector: #featured-categories{ margin: 0; ul{ margin: 0; li{ width: 33.33%; } } } This works, but is obviously not ideal. Can anyone help? I'm in a ruby 1.9.3 project running sass 3.2.9. Any pointers would be greatly appreciated.
The SCSS that you've provided should work fine. Check it out with SassMeister or http://jsfiddle.net/Kjanu/. It will compile to this: #featured-categories ul li { width: 33.33%; } So you've got something else going wrong in your setup.
Check Ruby HTTP response for success
How does one properly check the response from Net::HTTP::Get (for example) for "success" (i.e., a 2xx return code)? The documentation seems to be sadly silent on this simple question. I have: response=Net::HTTP.new( host, port ).request my_get_request # details not important After a bunch of Googling and near-random typing, I finally determined that this works: response.class < Net::HTTPSuccess Is that actually the canonical way to do it?
For Net::HTTP, yes, checking the class of the response object is the way to do it. Using kind_of? (aliased also as is_a?) is a bit clearer (but functionally equivalent to using <): response.kind_of? Net::HTTPSuccess Calling value on response will also raise a Net::HTTPError if the status code was not a successful one (what a poorly named method…). If you can, you may want to consider using a gem instead of Net::HTTP, as they often offer better APIs and performance. Typhoeus and HTTParty are two good ones, among others.
You can take advantage of Ruby's case statement which idiomatically performs class comparisons, thanks to its use of === under the hood. Here's an example from a JSON client that catches particular errors but otherwise just returns the server's message: case response when Net::HTTPSuccess JSON.parse response.body when Net::HTTPUnauthorized {'error' => "#{response.message}: username and password set and correct?"} when Net::HTTPServerError {'error' => "#{response.message}: try again later?"} else {'error' => response.message} end Note above Net::HTTPResponse parent classes (e.g. Net::HTTPServerError) work too.
If all you're looking to grab is the HTTP status code of an external API or website, then try Net::HTTP.get_response. Net::HTTP.get(url) returns a string. You won't be able to easily parse the header response from it: url = URI('http://example.com') string_response = Net::HTTP.get(url) # => "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style type=\"text/css\">\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 50px;\n background-color: #fff;\n border-radius: 1em;\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n #media (max-width: 700px) {\n body {\n background-color: #fff;\n }\n div {\n width: auto;\n margin: 0 auto;\n border-radius: 0;\n padding: 1em;\n }\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</h1>\n <p>This domain is established to be used for illustrative examples in documents. You may use this\n domain in examples without prior coordination or asking for permission.</p>\n <p>More information...</p>\n</div>\n</body>\n</html>\n" string_response.class # => String string_response.kind_of? Net::HTTPSuccess # => false status_response = Net::HTTP.get_response(url) # => #<Net::HTTPOK 200 OK readbody=true> status_response.class # => Net::HTTPOK status_response.kind_of? Net::HTTPSuccess # => true